python 闭包/嵌套函数在分配给外部数组时失败

标签 python closures

如果符号出现,Python函数的闭包似乎有问题 引用已分配:

def outer():
    p = []
    def gen():
        def touch(e):
            if e[0] == 'add':
                p.append(e);
            elif e[0] == 'rem':
                p = [ x for x in p if not (x[1] == e[1]) ]
        return touch
    f = gen()
    for i in [["add","test1"],["add","test2"],["rem","test2"],["rem","test1"]]:
        f(i)      

outer();

结果是:

Traceback (most recent call last):
  File "b.py", line 22, in <module>
    outer();
  File "b.py", line 20, in outer
    f(i)      
  File "b.py", line 14, in touch
    p.append(e);
UnboundLocalError: local variable 'p' referenced before assignment

如果我只是为了测试替换:

 -       p = [ x for x in p if not (x[1] == e[1]logig is) ]                                                                                                                                
 +       a = [ x for x in p if not (x[1] == e[1]) ]                                                                                                                                

错误消失了,但是代码不是我想要的。 python 闭包/嵌套函数是否会出现上述行为?我是否需要将数组包装在对象内部进行修改并仅调用函数?

另一方面,这个有效:

class o():
    def __init__(self):
        self.p = []
    def add(self,e):
        self.p.append(e);
    def rem(self,e):
        self.p = [ x for x in self.p if not (x[1] == e[1]) ]

def outer():
    p = o()
    def gen():
        def touch(e):
            if e[0] == 'add':
                p.add(e);
            elif e[0] == 'rem':
                p.rem(e)
        return touch
    f = gen()
    for i in [["add","test1"],["add","test2"],["rem","test2"],["rem","test1"]]:
        f(i)      

outer();

最佳答案

因为您在 touch 内分配 p,所以它成为 touch 中的局部变量,并有效地“隐藏”所有其他名称 p 在封闭范围内。为了告诉 Python 您实际上想要引用 outer 中的 p,您应该使用 nonlocal p,例如:

def outer():
    p = []
    def touch(e):
        # The following line is required to refer to outer's p
        nonlocal p
        if e[0] == 'add':
            p.append(e)
        elif e[0] == 'rem':
            p = [ x for x in p if not (x[1] == e[1]) ]
    for i in [["add","test1"],["add","test2"],["rem","test2"],["rem","test1"]]:
        touch(i)
outer()

您的第二个示例之所以有效,是因为您在 touch 的两种情况下都引用了 p 的属性,而不是进行赋值 (p = ... )。

参见nonlocal in the Python reference documentationscopes 的引用文档,和PEP 3104其中提出了nonlocal 语法。 nonlocal 仅存在于 Python 3 中,但是 there is a workaround如果有必要使用Python 2。

关于python 闭包/嵌套函数在分配给外部数组时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52411459/

相关文章:

python - 如何检查字符串是否是字符串列表中项目的子字符串

swift - 内部闭包的捕获列表是否需要将 `self` 重新声明为 `weak` 或 `unowned`?

rust - 如何在检查相同值的循环中使用可变捕获变量的闭包?

javascript - javascript 闭包的困惑

python - 使用 lambda 表达式进行字典理解无法产生所需的结果

rust - 返回一个改变其环境的闭包

python - 如何断言 pandas 数据帧过滤器的条件为 true

python - matplotlib 文本 bbox 的特定边距

python - 使用空间和时间变量在 python(scipy) 中聚类

python - 按行对之前的列进行计数