Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么将zip()返回的迭代器分配给变量会更快?_Python_Python 3.x - Fatal编程技术网

Python 为什么将zip()返回的迭代器分配给变量会更快?

Python 为什么将zip()返回的迭代器分配给变量会更快?,python,python-3.x,Python,Python 3.x,在以下代码中,time2-time1始终为负值: import time a = [num for num in range(int(1e6))] b = [num for num in range(int(1e6))] start_time = time.time() e = [(c, d) for c, d in zip(a, b)] time1 = time.time() - start_time print("--- %s seconds ---" % (time1)) start

在以下代码中,time2-time1始终为负值:

import time

a = [num for num in range(int(1e6))]
b = [num for num in range(int(1e6))]

start_time = time.time()
e = [(c, d) for c, d in zip(a, b)]
time1 = time.time() - start_time
print("--- %s seconds ---" % (time1))

start_time = time.time()
_zip = zip(a, b)
e = [(c, d) for c, d in _zip]
time2 = time.time() - start_time
print("--- %s seconds ---" % (time2))

print(time2-time1)
我认为这是因为在第一种情况下,我们需要调用zip()的次数要比在第二种情况下多得多。如果是这样的话,为什么zip不在每次调用iterable时都返回iterable中的第一个元素呢?zip()不是每次调用时都在a和b上创建新的迭代器吗?zip()是否对它创建的每个迭代器进行散列,并使用相同的散列存储迭代器以备将来调用


在对zip()调用进行迭代之前,将变量分配给它是好的还是坏的做法?性能提升通常值得额外的代码行吗?

我尝试将两个版本的代码包装成函数,使用
timeit
正确地进行基准测试,并使用
dis
检查生成的代码:

>>> import timeit
>>> def with_assignment():
...   _zip = zip(a, b)
...   return [(c, d) for c, d in _zip]
...
>>> def without_assignment():
...   return [(c, d) for c, d in zip(a, b)]
...
>>> a, b = list(range(1000000)), list(range(1000000))
>>> timeit.timeit(with_assignment, number=100)
16.1892559
>>> timeit.timeit(without_assignment, number=100) # indeed, it's a little slower,
16.3349139
>>> timeit.timeit(with_assignment, number=100)
16.261616600000004
>>> timeit.timeit(without_assignment, number=100) # and consistently so
16.42448019999999
>>> import dis # So let's look under the hood:
>>> dis.dis(with_assignment)
  2           0 LOAD_GLOBAL              0 (zip)
              2 LOAD_GLOBAL              1 (a)
              4 LOAD_GLOBAL              2 (b)
              6 CALL_FUNCTION            2
              8 STORE_FAST               0 (_zip)

  3          10 LOAD_CONST               1 (<code object <listcomp> at 0x00000226ABCA08A0, file "<stdin>", line 3>)
             12 LOAD_CONST               2 ('with_assignment.<locals>.<listcomp>')
             14 MAKE_FUNCTION            0
             16 LOAD_FAST                0 (_zip)
             18 GET_ITER
             20 CALL_FUNCTION            1
             22 RETURN_VALUE
>>> dis.dis(without_assignment)
  2           0 LOAD_CONST               1 (<code object <listcomp> at 0x00000226AD9299C0, file "<stdin>", line 2>)
              2 LOAD_CONST               2 ('without_assignment.<locals>.<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_GLOBAL              0 (zip)
              8 LOAD_GLOBAL              1 (a)
             10 LOAD_GLOBAL              2 (b)
             12 CALL_FUNCTION            2
             14 GET_ITER
             16 CALL_FUNCTION            1
             18 RETURN_VALUE
>>>
导入timeit >>>带有_赋值()的def: ... _zip=zip(a,b) ... 返回[(c,d)表示c,d在_-zip中] ... >>>不带_赋值的def(): ... 返回[(c,d)对于邮政编码中的c,d(a,b)] ... >>>a,b=列表(范围(1000000)),列表(范围(1000000)) >>>timeit.timeit(带_赋值,数字=100) 16.1892559 >>>timeit.timeit(没有赋值,数字=100)#实际上,它有点慢, 16.3349139 >>>timeit.timeit(带_赋值,数字=100) 16.261616600000004 >>>timeit.timeit(没有赋值,数字=100)#并且一直如此 16.42448019999999 >>>导入dis#那么让我们看看引擎盖下面: >>>dis.dis(带_分配) 2 0加载\u全局0(zip) 2负载_全局1(a) 4负载_全局2(b) 6调用函数2 8商店快0(_zip) 3 10加载常数1(<0x0000226ABCA08A0处的代码对象列表comp,文件“stdin”,第3行>) 12加载常数2('带有赋值…) 14生成函数0 16快速加载0(\u zip) 18获取ITER 20调用函数1 22返回值 >>>dis.dis(无分配) 2 0加载常数1(<0x0000226AD9299C0处的代码对象列表,文件“stdin”,第2行>) 2加载常数2('无分配…) 4生成函数0 6加载\u全局0(zip) 8负载_全局1(a) 10负载_全球2(b) 12调用函数2 14获取ITER 16调用函数1 18返回值 >>>
不过,恐怕我看不出明显的原因。除了额外的
STORE\u FAST
LOAD\u FAST
(设置并使用本地
\u zip
)之外,似乎所有的工作都在进行,尽管顺序不同。

您应该使用标准库模块
timeit
进行性能测试,我不认为这会改变这种情况下的结果。我真的不在乎时间是否有点短,我只想知道哪个更快,而且我个人认为这种方式更快。当我测试这个时,两个版本都没有一致的更快(正如预期的那样,片段之间的实际差异比随机变化和噪音的影响小得多)。真的吗?如果我将列表大小更改为1e8而不是1e6,则两者之间的差异约为8秒。它们之间的差别是巨大的。它看起来不像噪音,至少在我的机器上。无法复制。当我测试它时,两个版本的速度都不一致。