我维护的项目具有与此类似的功能定义:
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的,可能会有数十或数百个受此行为影响的函数调用。
答案 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
如你所见。 foo
和bar
相同,而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)
关于他们的文件或目的,我不知道。