python闭包/嵌套函数在分配给外部数组时失败
如果符号 被引用的文件被分配:python闭包/嵌套函数在分配给外部数组时失败,python,closures,Python,Closures,如果符号 被引用的文件被分配: 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
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
错误消失了,但是代码不是我想要的。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
,您应该使用非本地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=…
)
参见参考文档,其中提出了
非本地
语法非本地
仅存在于Python 3中,但如果有必要使用Python 2。如果您在touch函数中定义p而不是闭包,它似乎可以正常工作。或者你可以定义def touch(e,p):
并使用touch(i,p)
@Alexander:你说得对,我更改了标题/示例相当令人讨厌的陷阱。谢谢你的提示。
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()