带有生成器理解的“any"和不带括号的理解之间的区别? [英] Difference between 'any' with generator-comprehension and comprehension without parentheses?

查看:59
本文介绍了带有生成器理解的“any"和不带括号的理解之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

回顾我的一些代码,我意识到我写的东西本质上是:'

if (any(predicate for predicate in list_of_predicates)):# 做一点事

我预料到会出现这个语法错误,因为它缺少()"或[]".所以我在 ipython 中试了一下:

无括号:

在 [33]: timeit.repeat('any(True for x in xrange(10))', repeat=10)出[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)出[34]:[0.7183680534362793,0.6293261051177979,0.5045809745788574,0.4723200798034668,0.4649538993835449,0.5164840221405029,0.5919051170349121,0.5790350437164307,0.594775915145874,0.5718569755554199]

加速:

在 [52]: reg = timeit.repeat('any(True for x in xrange(10))', repeat=100)在 [53] 中:comp = timeit.repeat('any((True for x in xrange(10)))', repeat=100)在 [55] 中:avg(reg)出[55]:0.5245428466796875在 [56] 中:avg(comp)出[56]:0.5283565306663514在 [57] 中:stddev(reg)出[57]:0.05609485659272963在 [58] 中:stddev(comp)出[58]:0.058506353663056954在 [59] 中:reg[50]出[59]:0.46748805046081543在 [60] 中:comp[50]出[60]:0.5147180557250977

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

解决方案

这些表达式是等价的.性能差异是噪音.

来自原始genexp PEP:

<块引用>

如果一个函数调用只有一个位置参数,它可以是一个没有额外括号的生成器表达式,但在所有其他情况下,你必须把它加上括号.

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

<预><代码>>>>定义 f():... 任何(对于 x 范围内的 x 为真(10))...>>>定义 g():... 任何((对于 x 范围内的 x 为真(10)))...>>>dis.dis(f)2 0 LOAD_GLOBAL 0(任意)3 LOAD_CONST 1 (<代码对象<genexpr>在0000000002B46A30,文件<stdin>",第 2 行>)6 MAKE_FUNCTION 09 LOAD_GLOBAL 1 (xrange)12 LOAD_CONST 2 (10)15 CALL_FUNCTION 118 GET_ITER19 CALL_FUNCTION 122 CALL_FUNCTION 125 POP_TOP26 LOAD_CONST 0 (无)29 RETURN_VALUE>>>dis.dis(g)2 0 LOAD_GLOBAL 0(任意)3 LOAD_CONST 1 (<代码对象<genexpr>在0000000002BE0DB0,文件<stdin>",第 2 行>)6 MAKE_FUNCTION 09 LOAD_GLOBAL 1 (xrange)12 LOAD_CONST 2 (10)15 CALL_FUNCTION 118 GET_ITER19 CALL_FUNCTION 122 CALL_FUNCTION 125 POP_TOP26 LOAD_CONST 0 (无)29 RETURN_VALUE>>>f.__code__.co_consts(无,<代码对象<genexpr>在0000000002B46A30,文件<stdin>",第2行>,10)>>>dis.dis(f.__code__.co_consts[1]) # f 中 genexp 的代码对象2 0 LOAD_FAST 0 (.0)>>3 FOR_ITER 11(到 17)6 STORE_FAST 1 (x)9 LOAD_GLOBAL 0(真)12 YIELD_VALUE13 POP_TOP14 JUMP_ABSOLUTE 3>>17 LOAD_CONST 0 (无)20 RETURN_VALUE>>>dis.dis(g.__code__.co_consts[1]) # g中genexp的代码对象2 0 LOAD_FAST 0 (.0)>>3 FOR_ITER 11(到 17)6 STORE_FAST 1 (x)9 LOAD_GLOBAL 0(真)12 YIELD_VALUE13 POP_TOP14 JUMP_ABSOLUTE 3>>17 LOAD_CONST 0 (无)20 RETURN_VALUE

Reviewing some of my code and I realized I had written what is essentially:'

if (any(predicate for predicate in list_of_predicates)):
    # do something

I had expected this syntax error since it was missing '()' or '[]'. So I tried it in ipython:

Without bracketing:

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]

Generator comprehension:

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]

Ramping up:

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

There seems to be a marginal (possibly noise) performance advantage to not having the parentheses - ramping up the test it appears more like noise. Is there a fundamental difference between how these are processed?

解决方案

These expressions are equivalent. The performance difference is noise.

From the original genexp PEP:

if a function call has a single positional argument, it can be a generator expression without extra parentheses, but in all other cases you have to parenthesize it.

And viewing the disassembly, you can see that they compile to the same bytecode:

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

这篇关于带有生成器理解的“any"和不带括号的理解之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆