python closure with assigning outer variable inside inner function
我有这段代码:
1 2 3 4 5 6 7 8 9 10 11 12 | #!/usr/bin/env python def get_match(): cache=[] def match(v): if cache: return cache cache=[v] return cache return match m = get_match() m(1) |
如果我运行它,它会说:
1 | UnboundLocalError: local variable 'cache' referenced before assignment |
但如果我这样做:
1 2 3 4 5 6 7 8 9 10 | #!/usr/bin/env python def get(): y = 1 def m(v): return y + v return m a=get() a(1) |
它运行。
有清单吗?或者我的代码组织错误?
问题是变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def f(): v = 0 def x(): return v #works because v is read from the outer scope def y(): if v == 0: #fails because the variable v is assigned to below v = 1 #for python3: def z(): nonlocal v #tell python to search for v in the surrounding scope(s) if v == 0: v = 1 #works because you declared the variable as nonlocal |
全局变量的问题有点相同——每次分配给全局变量时都需要使用
对其背后原因的简短解释:python解释器将所有函数编译成
当函数执行时,解释器必须查找它遇到的每个变量引用。如果在编译期间发现变量是本地变量,则在函数f_locals字典中进行搜索。如果尚未将其分配给,则会引发遇到的异常。如果变量未在函数作用域中赋值,因而不是其局部变量的一部分,则会在周围作用域中查找该变量-如果在那里找不到该变量,则会引发类似的异常。
访问变量与分配变量不同。
全局变量的情况类似。您可以在任何函数中访问它们,但是如果您试图在不使用
不幸的是,对于本地函数,没有等效的
1 | cache=[v] |
用:
1 | cache[:] = [v] |
由于python看到
您可能想将其写为:
1 2 3 4 5 6 7 8 9 10 | def get_match(): cache=[] def match(v): if cache: return cache cache.append(v) return cache return match m = get_match() m(1) |
强烈建议阅读:执行模型-命名和绑定和PEP 227-静态嵌套范围
替换
1 2 | cache=[] def match(v): |
具有
1 | def match(v,cache=[]) |
说明:您的代码将EDCOX1 OR 0作为EDCOX1 OR 13的变量声明,EDCX1 OR 14引用的变量不知道(由于以下赋值)。但是,您确实希望EDCOX1×0是EDCOX1·16的命名空间的一部分。
我知道这样一个"恶意"用户可以重新定义缓存,但这是他们自己的错误。如果这是一个问题,则备选方案是:
1 2 3 4 5 6 7 | def match(v): try: if cache: return cache except NameError: cache = [] ... |
(见这里)