迭代是否some_dict.items()
与迭代 CPython 中相同项目的列表一样有效?
3 回答
这取决于您使用的 Python 版本。在 Python 2 中,some_dict.items()
创建一个新列表,这会占用一些额外的时间并占用额外的内存。另一方面,一旦创建列表,它就是一个列表,因此在列表创建开销完成后应该具有相同的性能特征。
在 Python 3 中,some_dict.items()
创建一个视图对象而不是列表,我预计创建和迭代items()
会比在 Python 2 中更快,因为不需要复制任何内容。但我也预计迭代一个已经创建的视图会比迭代一个已经创建的列表要慢一些,因为字典数据存储得有些稀疏,我相信 python 没有好的方法来避免迭代每个 bin字典——即使是空的。
在 Python 2 中,一些时间证实了我的直觉:
>>> some_dict = dict(zip(xrange(1000), reversed(xrange(1000))))
>>> some_list = zip(xrange(1000), xrange(1000))
>>> %timeit for t in some_list: t
10000 loops, best of 3: 25.6 us per loop
>>> %timeit for t in some_dict.items(): t
10000 loops, best of 3: 57.3 us per loop
迭代的items
速度大约是原来的两倍。使用iteritems
速度有点快...
>>> %timeit for t in some_dict.iteritems(): t
10000 loops, best of 3: 41.3 us per loop
但是迭代列表本身与迭代任何其他列表基本相同:
>>> some_dict_list = some_dict.items()
>>> %timeit for t in some_dict_list: t
10000 loops, best of 3: 26.1 us per loop
items
Python 3 可以比 Python 2 更快地创建和迭代(与上面的 57.3 us 相比):
>>> some_dict = dict(zip(range(1000), reversed(range(1000))))
>>> %timeit for t in some_dict.items(): t
10000 loops, best of 3: 33.4 us per loop
但是创建视图的时间可以忽略不计;迭代实际上比列表慢。
>>> some_list = list(zip(range(1000), reversed(range(1000))))
>>> some_dict_view = some_dict.items()
>>> %timeit for t in some_list: t
10000 loops, best of 3: 18.6 us per loop
>>> %timeit for t in some_dict_view: t
10000 loops, best of 3: 33.3 us per loop
这意味着在 Python 3 中,如果您想对字典中的项目进行多次迭代,并且性能至关重要,您可以通过将视图缓存为列表来获得 30% 的加速。
>>> some_list = list(some_dict_view)
>>> %timeit for t in some_list: t
100000 loops, best of 3: 18.6 us per loop
一个小基准向我展示了迭代列表肯定更快。
def iterlist(list_):
i = 0
for _ in list_:
i += 1
return i
def iterdict(dict_):
i = 0
for _ in dict_.iteritems():
i += 1
return i
def noiterdict(dict_):
i = 0
for _ in dict_.items():
i += 1
return i
list_ = range(1000000)
dict_ = dict(zip(range(1000000), range(1000000)))
在 Python 2.7 (Kubuntu) 上使用 IPython 进行测试:
%timeit iterlist(list_)
10 loops, best of 3: 28.5 ms per loop
%timeit iterdict(dict_)
10 loops, best of 3: 39.7 ms per loop
%timeit noiterdict(dict_)
10 loops, best of 3: 86.1 ms per loop
Although iterating through some_list
is 2x speedup than some_dict.items()
, but iterating through some_list
by index is almost as same as iterating through some_dict
by key.
K = 1000000
some_dict = dict(zip(xrange(K), reversed(xrange(K))))
some_list = zip(xrange(K), xrange(K))
%timeit for t in some_list: t
10 loops, best of 3: 55.7 ms per loop
%timeit for i in xrange(len(some_list)):some_list[i]
10 loops, best of 3: 94 ms per loop
%timeit for key in some_dict: some_dict[key]
10 loops, best of 3: 115 ms per loop
%timeit for i,t in enumerate(some_list): t
10 loops, best of 3: 103 ms per loop