【问题标题】:Why does locals() return a strange self referential list?为什么 locals() 返回一个奇怪的自引用列表?
【发布时间】:2014-04-13 23:46:00
【问题描述】:

所以我使用 locals() 来获取函数中的一些参数。效果很好:

def my_function(a, b):
    print locals().values()

>>> my_function(1,2)
[1, 2]

标准的东西。但现在让我们介绍一个列表推导式:

def my_function(a, b):
    print [x for x in locals().values()]

>>> my_function(1,2)
[[...], 1, 2]

嗯?为什么要插入自引用?

【问题讨论】:

  • 不是在 Python 2.7 中它没有。 Python 2.6,是的。
  • 为什么只打印值?你为什么不把钥匙打印出来,看看什么指的是什么?
  • @MartijnPieters 是 2.6 中的错误吗?它在 2.7 中消失了,是的,但不幸的是我没有安装 2.7 的奢侈。
  • @LittleBobbyTables:很可能是列表推导的命名空间处理发生了变化; list comp 输出似乎存储在 locals 命名空间中。我也在 Python 2.5 中看到它。
  • @LittleBobbyTables:如果您需要在列表理解中过滤掉它,请使用[v for k, v in locals().iteritems() if not k.startswith('_[')]

标签: python list-comprehension python-2.6 python-internals locals


【解决方案1】:

2.7 和 3.1 之前的 Python 版本使用次优字节码来生成列表解析。在那些 Python 版本中,列表推导式存储在局部变量中(如果在模块范围内,甚至是全局变量):

>>> import dis
>>> def foo():
...     return [x for x in y]
... 
>>> dis.dis(foo)
  2           0 BUILD_LIST               0
              3 DUP_TOP             
              4 STORE_FAST               0 (_[1])
              7 LOAD_GLOBAL              0 (y)
             10 GET_ITER            
        >>   11 FOR_ITER                13 (to 27)
             14 STORE_FAST               1 (x)
             17 LOAD_FAST                0 (_[1])
             20 LOAD_FAST                1 (x)
             23 LIST_APPEND         
             24 JUMP_ABSOLUTE           11
        >>   27 DELETE_FAST              0 (_[1])
             30 RETURN_VALUE        

_[1] 局部变量是正在进行的列表。当嵌套列表推导时,它会使用递增的整数来引用结果:

>>> def bar():
...     return [[x for x in y] for z in spam]
... 
>>> dis.dis(bar)
  2           0 BUILD_LIST               0
              3 DUP_TOP             
              4 STORE_FAST               0 (_[1])
              7 LOAD_GLOBAL              0 (spam)
             10 GET_ITER            
        >>   11 FOR_ITER                40 (to 54)
             14 STORE_FAST               1 (z)
             17 LOAD_FAST                0 (_[1])
             20 BUILD_LIST               0
             23 DUP_TOP             
             24 STORE_FAST               2 (_[2])
             27 LOAD_GLOBAL              1 (y)
             30 GET_ITER            
        >>   31 FOR_ITER                13 (to 47)
             34 STORE_FAST               3 (x)
             37 LOAD_FAST                2 (_[2])
             40 LOAD_FAST                3 (x)
             43 LIST_APPEND         
             44 JUMP_ABSOLUTE           31
        >>   47 DELETE_FAST              2 (_[2])
             50 LIST_APPEND         
             51 JUMP_ABSOLUTE           11
        >>   54 DELETE_FAST              0 (_[1])
             57 RETURN_VALUE        

通过循环locals().values(),您在返回值中包含了对正在处理的列表的引用。请注意,字节码使用DELETE_FAST 来清理本地名称,以尽量避免命名空间污染。

这已针对 Python 3.1 和 2.7 进行了优化,请参阅 issue 2183。正在构建的列表结果被移动到堆栈中。优化更改了 LIST_APPEND 字节码以引用堆栈上要附加到的列表,消除了在开始时使用 DUP_TOP -> STORE_FAST、每次迭代使用 LOAD_FAST 和列表理解后使用 DELETE_FAST 的需要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    相关资源
    最近更新 更多