python - 装饰器中声明的非局部变量没有绑定(bind)

标签 python

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 dynamicnonlocalglobal 语句告诉编译器更改名称设置的范围。 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 or global.

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黑客的非常高级的方面。

例如,通过访问源代码(通常是这种情况),您可以使用 inspectast 来合并 function< 的抽象语法树returning 中以创建嵌套范围,然后将该新树编译成可以执行您想要的操作的字节码。或者,您必须对两个函数的字节码执行类似的操作,以使 returning 生成一个闭包,并且 function() 将该闭包作为 的值变量。这需要深入了解 Python 闭包的工作原理,以及编译器生成什么字节码来处理闭包。

所有这些意味着您可以更轻松地找到解决问题的不同方法。也许使用带有状态的类来改变不同上下文中的状态等。

关于python - 装饰器中声明的非局部变量没有绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50051496/

相关文章:

python - argmin 方法的返回类型

Python从字典列表列表创建列表

python - 将不同数据帧中的列添加到 PySpark 中的目标数据帧

python - 在 Python 中读取 .csv 而不遍历整个文件?

python - 比较元组列表 - 无论位置如何都相等

Python Matplotlib Basemap 在 map 图上叠加小图像

python - 如何将列表列表转换为数据框并将列表的第一个元素作为索引

python - 如何在 Python 自己的调试器 (PDB) 中执行多行语句

python - 在多列 Pandas 上应用 lambda 行

python - pkg_resources.DistributionNotFound : PIL