【问题标题】:How do python Set Comprehensions work?python Set Comprehensions 是如何工作的?
【发布时间】:2013-12-28 02:12:21
【问题描述】:

Q1 - 以下是 set() 还是 generator expressionset comprehension? (或者它们是否相同?如果是,listdict 理解是否也在生成器上对应类型转换?)

my_set = {x for x in range(10)}

Q2 - 评估是否考虑重复值,然后通过应用 set() 将其删除?

dup_set = {x for x in [0, 1, 2, 0, 1, 2]}

理解的执行(速度方面)是否比常规的for 循环更好?

更新 - 我尝试使用timeit 进行速度比较。我不确定我是否只是(公平)。

C:\>python -m timeit "s = set()" "for x in range(10):" "
  s.add(x)"
100000 loops, best of 3: 2.3 usec per loop

C:\>python -m timeit "s = {x for x in range(10)}"
1000000 loops, best of 3: 1.68 usec per loop

现在,使用一些条件

C:\>python -m timeit "s = set()" "for x in range(10):" "
  if x%2: s.add(x)"
100000 loops, best of 3: 2.27 usec per loop

C:\>python -m timeit "s = {x for x in range(10) if x%2}"
1000000 loops, best of 3: 1.83 usec per loop

那么,有很大的不同,是不是因为 c 中硬编码的功能?

【问题讨论】:

标签: python set generator set-comprehension


【解决方案1】:

Q1:是的,是的,是的,是的。或者至少他们的行为是这样的。如果您查看字节码,情况会有所不同。让我们反汇编这段代码(Python 2.7):

def list_comp(l):
    return [x+1 for x in l]

def dict_comp(l):
    return {x+1:0 for x in l}

def set_comp(l):
    return {x+1 for x in l}

def generator(l):
    return (x+1 for x in l)

这就是你得到的:

Disassembly of list_comp:
  2           0 BUILD_LIST              0
              3 LOAD_FAST               0 (l)
              6 GET_ITER            
        >>    7 FOR_ITER               16 (to 26)
             10 STORE_FAST              1 (x)
             13 LOAD_FAST               1 (x)
             16 LOAD_CONST              1 (1)
             19 BINARY_ADD          
             20 LIST_APPEND             2
             23 JUMP_ABSOLUTE           7
        >>   26 RETURN_VALUE
Disassembly of dict_comp:
  5           0 LOAD_CONST              1 (<code object <dictcomp> at 029DEE30)
              3 MAKE_FUNCTION           0
              6 LOAD_FAST               0 (l)
              9 GET_ITER            
             10 CALL_FUNCTION           1
             13 RETURN_VALUE  
Disassembly of set_comp:
  8           0 LOAD_CONST              1 (<code object <setcomp> at 029DECC8)
              3 MAKE_FUNCTION           0
              6 LOAD_FAST               0 (l)
              9 GET_ITER            
             10 CALL_FUNCTION           1
             13 RETURN_VALUE  
Disassembly of generator:
 11           0 LOAD_CONST              1 (<code object <genexpr> at 02A8FD58)
              3 MAKE_FUNCTION           0
              6 LOAD_FAST               0 (l)
              9 GET_ITER            
             10 CALL_FUNCTION           1
             13 RETURN_VALUE                     

字典理解、集合理解和生成器的字节码几乎不一样。它们都加载一个代码对象(&lt;dictcomp&gt;&lt;setcomp&gt;&lt;genexpr&gt;),然后从中创建一个可调用函数。列表理解是不同的,因为它会生成与您的列表理解相对应的字节码。这次它是解释的,因此不是原生的。

Q2 :它并没有真正考虑重复值,因为它会根据您提供的列表创建一个理解。然后它用推导式创建集合。

关于时间: List/Dict/Set 理解往往比其他任何东西都快。即使它们被解释,生成的字节码也会针对大多数情况进行优化,使用特殊的字节码指令,如SET_ADDLIST_APPENDMAP_ADD

【讨论】:

  • 我不确定,我会检查一下。
  • 显然,它的编写内容取决于您使用的 Python(CPython、IronPython、Jython、PyPy 等)。然而,重要的一点是它是 native 即不解释的。
  • 另外,“for loop with add/append calls”版本会导致每次迭代调用一个函数,这意味着额外的堆栈帧(更不用说函数的名称必须首先解析,这是一个数组查找和一个字典查找)...推导式不做这些。
  • 在 Python 3 中,列表推导也有自己的范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-17
  • 2011-08-04
  • 1970-01-01
  • 1970-01-01
  • 2020-09-05
相关资源
最近更新 更多