为什么 co_varnames return 不列出所有变量名?
Why doesn't co_varnames return list of all the variable names?
为什么下面代码片段的结果不同?
def Foo():
i = 0
def Bar():
nonlocal i
i = 1
return Bar()
print(Foo.__code__.co_varnames)
# it will print: ('Bar',)
def Foo():
i = 0
def Bar():
i = 1
return Bar()
print(Foo.__code__.co_varnames)
# it will print: ('i', 'Bar',)
如你所见,结果不一样,不知道为什么不一样。
好的,这有点微妙。虽然 co_varnames
应该给你所有 local 变量,在这种情况下,i
实际上是 Bar
中的一个自由变量,所以它在 Bar
的闭包.
注意当我们分解字节码时会发生什么:
In [2]: def Foo():
...: i = 0
...: def Bar():
...: nonlocal i
...: i = 1
...: return Bar()
...:
In [3]: Foo.__code__.co_varnames
Out[3]: ('Bar',)
In [4]: import dis
In [5]: dis.dis(Foo)
2 0 LOAD_CONST 1 (0)
2 STORE_DEREF 0 (i)
3 4 LOAD_CLOSURE 0 (i)
6 BUILD_TUPLE 1
8 LOAD_CONST 2 (<code object Bar at 0x101072be0, file "<ipython-input-4-a3a062461e32>", line 3>)
10 LOAD_CONST 3 ('Foo.<locals>.Bar')
12 MAKE_FUNCTION 8 (closure)
14 STORE_FAST 0 (Bar)
6 16 LOAD_FAST 0 (Bar)
18 CALL_FUNCTION 0
20 RETURN_VALUE
Disassembly of <code object Bar at 0x101072be0, file "<ipython-input-4-a3a062461e32>", line 3>:
5 0 LOAD_CONST 1 (1)
2 STORE_DEREF 0 (i)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE
注意,操作码是 STORE_DEREF
而不是 STORE_FAST
。所以,考虑:
In [9]: def Foo():
...: i = 0
...: def Bar():
...: nonlocal i
...: i = 1
...: return Bar
...:
In [10]: bar = Foo()
In [11]: bar.__closure__
Out[11]: (<cell at 0x1040a7940: int object at 0x100980bc0>,)
由于它在嵌套函数中被引用,这将在 co_cellvars
:
中可用
In [12]: foo_code = Foo.__code__
In [13]: foo_code.co_cellvars
Out[13]: ('i',)
这在内部类型的数据模型 documentation 中有解释:
co_varnames
is a tuple containing the
names of the local variables (starting with the argument names);
co_cellvars
is a tuple containing the names of local variables that
are referenced by nested functions; co_freevars
is a tuple containing
the names of free variables...
所以要获得所有局部变量你需要:
In [16]: Foo.__code__.co_varnames + Foo.__code__.co_cellvars
Out[16]: ('Bar', 'i')
为什么下面代码片段的结果不同?
def Foo():
i = 0
def Bar():
nonlocal i
i = 1
return Bar()
print(Foo.__code__.co_varnames)
# it will print: ('Bar',)
def Foo():
i = 0
def Bar():
i = 1
return Bar()
print(Foo.__code__.co_varnames)
# it will print: ('i', 'Bar',)
如你所见,结果不一样,不知道为什么不一样。
好的,这有点微妙。虽然 co_varnames
应该给你所有 local 变量,在这种情况下,i
实际上是 Bar
中的一个自由变量,所以它在 Bar
的闭包.
注意当我们分解字节码时会发生什么:
In [2]: def Foo():
...: i = 0
...: def Bar():
...: nonlocal i
...: i = 1
...: return Bar()
...:
In [3]: Foo.__code__.co_varnames
Out[3]: ('Bar',)
In [4]: import dis
In [5]: dis.dis(Foo)
2 0 LOAD_CONST 1 (0)
2 STORE_DEREF 0 (i)
3 4 LOAD_CLOSURE 0 (i)
6 BUILD_TUPLE 1
8 LOAD_CONST 2 (<code object Bar at 0x101072be0, file "<ipython-input-4-a3a062461e32>", line 3>)
10 LOAD_CONST 3 ('Foo.<locals>.Bar')
12 MAKE_FUNCTION 8 (closure)
14 STORE_FAST 0 (Bar)
6 16 LOAD_FAST 0 (Bar)
18 CALL_FUNCTION 0
20 RETURN_VALUE
Disassembly of <code object Bar at 0x101072be0, file "<ipython-input-4-a3a062461e32>", line 3>:
5 0 LOAD_CONST 1 (1)
2 STORE_DEREF 0 (i)
4 LOAD_CONST 0 (None)
6 RETURN_VALUE
注意,操作码是 STORE_DEREF
而不是 STORE_FAST
。所以,考虑:
In [9]: def Foo():
...: i = 0
...: def Bar():
...: nonlocal i
...: i = 1
...: return Bar
...:
In [10]: bar = Foo()
In [11]: bar.__closure__
Out[11]: (<cell at 0x1040a7940: int object at 0x100980bc0>,)
由于它在嵌套函数中被引用,这将在 co_cellvars
:
In [12]: foo_code = Foo.__code__
In [13]: foo_code.co_cellvars
Out[13]: ('i',)
这在内部类型的数据模型 documentation 中有解释:
co_varnames
is a tuple containing the names of the local variables (starting with the argument names);co_cellvars
is a tuple containing the names of local variables that are referenced by nested functions;co_freevars
is a tuple containing the names of free variables...
所以要获得所有局部变量你需要:
In [16]: Foo.__code__.co_varnames + Foo.__code__.co_cellvars
Out[16]: ('Bar', 'i')