'任何'之间的区别没有括号的生成器理解和理解?

时间:2018-03-19 01:34:56

标签: python-2.7

回顾一下我的一些代码,我意识到自己写的基本上是:'

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

没有括号似乎有一个边际(可能是噪音)的性能优势 - 加快测试它看起来更像是噪音。 这些处理方式之间是否有根本区别

1 个答案:

答案 0 :(得分:2)

这些表达式是等效的。性能差异是噪音。

来自original genexp PEP

  

如果函数调用具有单个位置参数,则它可以是没有额外括号的生成器表达式,但在所有其他情况下,您必须将其括起来。

查看反汇编,您可以看到它们编译为相同的字节码:

>>> 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