以下代码片段是否会在每个循环中创建和销毁常量列表,这会产生任何(尽管很小)开销,还是只创建一次列表?
for i in <some-type-of-iterable>:
if i in [1,3,5,18,3457,40567]:
print(i)
我问的是 Python“标准”(例如存在的标准)和常见的 CPython 实现。
我知道这个例子是人为设计的,而且尝试担心使用 CPython 的性能是愚蠢的,但我只是好奇。
最佳答案
这取决于 python 实现和版本以及“常量列表”的使用方式。在 Cpython2.7.10 上以您的示例为例,答案似乎是 if
语句条件中的列表仅创建一次...
>>> def foo():
... for i in iterable:
... if i in [1, 3, 5]:
... print(i)
...
>>> import dis
>>> dis.dis(foo)
2 0 SETUP_LOOP 34 (to 37)
3 LOAD_GLOBAL 0 (iterable)
6 GET_ITER
>> 7 FOR_ITER 26 (to 36)
10 STORE_FAST 0 (i)
3 13 LOAD_FAST 0 (i)
16 LOAD_CONST 4 ((1, 3, 5))
19 COMPARE_OP 6 (in)
22 POP_JUMP_IF_FALSE 7
4 25 LOAD_FAST 0 (i)
28 PRINT_ITEM
29 PRINT_NEWLINE
30 JUMP_ABSOLUTE 7
33 JUMP_ABSOLUTE 7
>> 36 POP_BLOCK
>> 37 LOAD_CONST 0 (None)
40 RETURN_VALUE
注意:16 LOAD_CONST 4 ((1, 3, 5))
Python 的窥孔优化器已将我们的列表转换为元组(感谢 python!)并将其存储为常量。请注意,如果窥孔优化器知道您作为程序员绝对没有办法获得对列表的引用(否则,您可以改变列表并更改代码的含义),则它只能对对象进行这些转换。据我所知,他们只对 list
、set
文字进行优化,这些文字完全由常量组成,并且是 in中的 RHS
运算符。可能还有其他我不知道的情况(dis.dis
是您找到这些优化的 friend )。
我在上面已经暗示过,但是你可以在更新的 python 版本中用集合文字做同样的事情(在 python3.2+ 中,set
被转换为常量 frozenset
).这样做的好处是 set
/frozenset
的成员资格测试平均比 list
/tuple
快。
关于python - 是否在每次通过时构造/删除循环中使用的常量列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37421183/