def decorator(func):
def returning():
var = 1
func()
print(var)
return(returning)
@decorator
def function():
nonlocal var
var = 5
function()
var 在调用 func() 之前在 returned() 函数中声明,但我收到绑定(bind)错误。
我不明白为什么会发生这种情况。
最佳答案
Python 在编译时确定作用域,使得 scope model static, not dynamic 。 nonlocal
和 global
语句告诉编译器更改名称设置的范围。 nonlocal
告诉编译器一个给定的名称将被分配为一个闭包,存在于一个封闭的范围内。请参阅Naming and binding section Python执行模型文档的:
If a name is bound in a block, it is a local variable of that block, unless declared as
nonlocal
orglobal
.
和
Each assignment or import statement occurs within a block defined by a class or function definition or at the module level (the top-level code block).
和
A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block. If the definition occurs in a function block, the scope extends to any blocks contained within the defining one, unless a contained block introduces a different binding for the name.
因此,只有函数定义、类定义和模块级别是进行赋值的 block 。 nonlocal
只能作用于嵌套范围内的名称:
The
nonlocal
statement causes corresponding names to refer to previously bound variables in the nearest enclosing function scope.
function()
不是嵌套 block ,没有封闭的函数作用域。
装饰器是一个运行时功能,并且不会产生新的封闭函数作用域。您没有将 function()
嵌套在装饰器内,您只传入了对函数对象的引用。该函数已经创建,编译已完成,并且名称的范围已确定。
做你想做的事的唯一方法需要重新编译或字节码操作,这两个主题都属于Python黑客的非常高级的方面。
例如,通过访问源代码(通常是这种情况),您可以使用 inspect
和 ast
来合并 function< 的抽象语法树
到 returning
中以创建嵌套范围,然后将该新树编译成可以执行您想要的操作的字节码。或者,您必须对两个函数的字节码执行类似的操作,以使 returning
生成一个闭包,并且 function()
将该闭包作为 的值变量
。这需要深入了解 Python 闭包的工作原理,以及编译器生成什么字节码来处理闭包。
所有这些意味着您可以更轻松地找到解决问题的不同方法。也许使用带有状态的类来改变不同上下文中的状态等。
关于python - 装饰器中声明的非局部变量没有绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50051496/