我预期以下结果会导致y
成为自由变量:
def f(x):
return x + y
然而,f.__code__.co_freevars
等于()
,f.__code__.co_varnames
等于('x',)
,并且f.__code__.co_names
等于('y',)
。
那么,究竟是什么会导致变量用于填充co_freevars
呢?
似乎只有当存在闭包时才填充co_freevars
,即在外部函数中定义内部函数。
模块级函数将__closure__
设置为None
,尽管访问了非本地变量:
y = 1
def foo(x):
return x + y
print(foo.__closure__)
print(foo.__code__.co_freevars)
输出:
None
()
与相反
def bar():
y = 1
def baz(x):
return x + y
print(baz.__closure__)
print(baz.__closure__[0].cell_contents)
print(baz.__code__.co_freevars)
bar()
输出:
(<cell at 0x7fa8fbbf0700: int object at 0x7fa8fbc7a930>,)
1
('y',)
这是对@mortes答案的补充。
文档定义了一个自由变量,因此:
如果名称绑定在块中,则它是该块的局部变量,除非声明为
nonlocal
或global
。如果一个名称在模块级别绑定,那么它就是一个全局变量。(模块代码块的变量是局部的和全局的。(如果在代码块中使用了一个变量,但没有在那里定义,则该变量是自由变量。
以下部分的警告:
global
语句与同一块中的名称绑定操作具有相同的作用域。如果自由变量最近的封闭范围包含全局语句,则该自由变量将被视为全局变量。
再往下看,一个明确的例子:
自由变量的名称解析发生在运行时,而不是编译时。这意味着以下代码将打印42:
i = 10 def f(): print(i) i = 42 f()
但形式定义与该术语如何用于co_freevars
无关。这在inspect
:的文档中明确列出
+------+-------------+------------------------------------------------------------------------+ | code | co_freevars | tuple of names of free variables (referenced via a function’s closure) | +------+-------------+------------------------------------------------------------------------+
因此code.co_freevars
是所有引用LEGB的E部分的自由变量的一个非常特定的子集。