回顾一下我的一些代码,我意识到自己写的基本上是:'
if (any(predicate for predicate in list_of_predicates)):
# do something
我原本期望这种语法错误,因为它丢失了'()'或者' []'。所以我在ipython中试了一下:
没有包围:
In [33]: timeit.repeat('any(True for x in xrange(10))', repeat=10)
Out[33]:
[0.502741813659668,
0.49950194358825684,
0.6626348495483398,
0.5485308170318604,
0.5268769264221191,
0.6033108234405518,
0.4647831916809082,
0.45836901664733887,
0.46139097213745117,
0.4977281093597412]
生成器理解:
In [34]: timeit.repeat('any((True for x in xrange(10)))', repeat=10)
Out[34]:
[0.7183680534362793,
0.6293261051177979,
0.5045809745788574,
0.4723200798034668,
0.4649538993835449,
0.5164840221405029,
0.5919051170349121,
0.5790350437164307,
0.594775915145874,
0.5718569755554199]
加速:
In [52]: reg = timeit.repeat('any(True for x in xrange(10))', repeat=100)
In [53]: comp = timeit.repeat('any((True for x in xrange(10)))', repeat=100)
In [55]: avg(reg)
Out[55]: 0.5245428466796875
In [56]: avg(comp)
Out[56]: 0.5283565306663514
In [57]: stddev(reg)
Out[57]: 0.05609485659272963
In [58]: stddev(comp)
Out[58]: 0.058506353663056954
In [59]: reg[50]
Out[59]: 0.46748805046081543
In [60]: comp[50]
Out[60]: 0.5147180557250977
没有括号似乎有一个边际(可能是噪音)的性能优势 - 加快测试它看起来更像是噪音。 这些处理方式之间是否有根本区别?
答案 0 :(得分:2)
这些表达式是等效的。性能差异是噪音。
如果函数调用具有单个位置参数,则它可以是没有额外括号的生成器表达式,但在所有其他情况下,您必须将其括起来。
查看反汇编,您可以看到它们编译为相同的字节码:
>>> def f():
... any(True for x in xrange(10))
...
>>> def g():
... any((True for x in xrange(10)))
...
>>> dis.dis(f)
2 0 LOAD_GLOBAL 0 (any)
3 LOAD_CONST 1 (<code object <genexpr> at 0000000002
B46A30, file "<stdin>", line 2>)
6 MAKE_FUNCTION 0
9 LOAD_GLOBAL 1 (xrange)
12 LOAD_CONST 2 (10)
15 CALL_FUNCTION 1
18 GET_ITER
19 CALL_FUNCTION 1
22 CALL_FUNCTION 1
25 POP_TOP
26 LOAD_CONST 0 (None)
29 RETURN_VALUE
>>> dis.dis(g)
2 0 LOAD_GLOBAL 0 (any)
3 LOAD_CONST 1 (<code object <genexpr> at 0000000002
BE0DB0, file "<stdin>", line 2>)
6 MAKE_FUNCTION 0
9 LOAD_GLOBAL 1 (xrange)
12 LOAD_CONST 2 (10)
15 CALL_FUNCTION 1
18 GET_ITER
19 CALL_FUNCTION 1
22 CALL_FUNCTION 1
25 POP_TOP
26 LOAD_CONST 0 (None)
29 RETURN_VALUE
>>> f.__code__.co_consts
(None, <code object <genexpr> at 0000000002B46A30, file "<stdin>", line 2>, 10)
>>> dis.dis(f.__code__.co_consts[1]) # the genexp's code object in f
2 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 11 (to 17)
6 STORE_FAST 1 (x)
9 LOAD_GLOBAL 0 (True)
12 YIELD_VALUE
13 POP_TOP
14 JUMP_ABSOLUTE 3
>> 17 LOAD_CONST 0 (None)
20 RETURN_VALUE
>>> dis.dis(g.__code__.co_consts[1]) # the genexp's code object in g
2 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 11 (to 17)
6 STORE_FAST 1 (x)
9 LOAD_GLOBAL 0 (True)
12 YIELD_VALUE
13 POP_TOP
14 JUMP_ABSOLUTE 3
>> 17 LOAD_CONST 0 (None)
20 RETURN_VALUE