`locals()中无法访问的`.0`变量是否会影响内存或性能?

时间:2012-01-08 07:57:14

标签: python

我维护的项目具有与此类似的功能定义:

def f(a, (b1, b2), c):
    print locals()

在调试代码时,我发现.1中出现locals()个键,其值为(b1, b2)。快速检查显示函数定义如下:

def f((a1, a2)):
    print locals()

.0中的locals()密钥的值为(a1, a2)。我对此行为感到惊讶,但在Python文档中找不到任何信息。

我的问题是:这些否则无法访问的位置变量会影响内存或性能吗?他们在任何地方记录?他们的目的是什么?

有问题的项目是feedparser,它是基于SAX的,可能会有数十或数百个受此行为影响的函数调用。

2 个答案:

答案 0 :(得分:5)

所以pep 3113正如artur gaspar指出的那样,包含一个完整的答案。它还列出了一大堆原因,为什么这可能不是一个很好的模式。其中一个你在调试的烦人副作用中发现。一个更大的一个是我认为你的代码会破坏过渡到python3,但我不确定/仍然是2.7个人。

我想玩会发生什么。看一些反汇编的字节码,我们可以看到这三个函数会发生什么(扰码:foo和bar有相同的字节码):

from dis import dis

def foo(a, (b, c) ,d):
    return a + b + c + d

def bar(a, b_c, d):
    b, c = b_c
    return a + b + c + d

def baz(a, b, c, d):
    return a + b + c + d

print '\nfoo:'
dis(foo)
print '\nbar:'
dis(bar)
print '\nbaz:'
dis(baz)

收率:

foo:
  3           0 LOAD_FAST                1 (.1)
              3 UNPACK_SEQUENCE          2
              6 STORE_FAST               3 (b)
              9 STORE_FAST               4 (c)

  4          12 LOAD_FAST                0 (a)
             15 LOAD_FAST                3 (b)
             18 BINARY_ADD          
             19 LOAD_FAST                4 (c)
             22 BINARY_ADD          
             23 LOAD_FAST                2 (d)
             26 BINARY_ADD          
             27 RETURN_VALUE        


bar:
  7           0 LOAD_FAST                1 (b_c)
              3 UNPACK_SEQUENCE          2
              6 STORE_FAST               3 (b)
              9 STORE_FAST               4 (c)

  8          12 LOAD_FAST                0 (a)
             15 LOAD_FAST                3 (b)
             18 BINARY_ADD          
             19 LOAD_FAST                4 (c)
             22 BINARY_ADD          
             23 LOAD_FAST                2 (d)
             26 BINARY_ADD          
             27 RETURN_VALUE        


baz:
 11           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 BINARY_ADD          
              7 LOAD_FAST                2 (c)
             10 BINARY_ADD          
             11 LOAD_FAST                3 (d)
             14 BINARY_ADD          
             15 RETURN_VALUE        

如你所见。 foobar相同,而baz会跳过解包。所以,是的,这会影响性能,但只有元组解包才能实现,除了非常小的函数和玩具示例(比如这个; P),这应该可以忽略不计。

答案 1 :(得分:3)

是的,它们会影响性能。

>>> import timeit
>>> 
>>> 
>>> def function_1(a, (b1, b2), c):
...     locals()
... 
>>> def function_2(a, b1, b2, c):
...     locals()
... 
>>> 
>>> object_1 = object()
>>> object_2 = object()
>>> object_3 = object()
>>> tuple_of_objects_2_and_3 = (object_2, object_3)
>>> object_4 = object()
>>> 
>>> n = 100000000
>>> 
>>> time_1 = timeit.timeit(lambda: function_1(object_1, tuple_of_objects_2_and_3, 
...                                           object_4),
...                        number=n)
>>> time_2 = timeit.timeit(lambda: function_2(object_1, object_2, object_3, 
...                                           object_4), 
...                        number=n)
>>> 
>>> print(time_1, time_2)
(170.2440218925476, 151.92010402679443)

关于他们的文件或目的,我不知道。