究竟是什么会导致函数的 __code__.co_freevars 为非空?



我预期以下结果会导致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答案的补充。

文档定义了一个自由变量,因此:

如果名称绑定在块中,则它是该块的局部变量,除非声明为nonlocalglobal。如果一个名称在模块级别绑定,那么它就是一个全局变量。(模块代码块的变量是局部的和全局的。(如果在代码块中使用了一个变量,但没有在那里定义,则该变量是自由变量

以下部分的警告:

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部分的自由变量的一个非常特定的子集。

相关内容

最新更新