我有这段代码:
#!/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)
如果我运行它,它说:
UnboundLocalError: local variable 'cache' referenced before assignment
但如果我这样做:
#!/usr/bin/env python
def get():
y = 1
def m(v):
return y + v
return m
a=get()
a(1)
它运行。
列表中有什么东西吗?或者我的代码组织错了?
答案 0 :(得分:25)
问题是变量cache
不在函数匹配的范围内。如果您只想在第二个示例中阅读它,这不是问题,但如果您要分配它,python会将其解释为局部变量。如果您正在使用python 3,则可以使用nonlocal
关键字来解决此问题 - 对于python 2,遗憾的是没有简单的解决方法。
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
问题与全局变量有些相同 - 每次分配全局变量时都需要使用global
,但不能读取它。
对背后原因的简短解释:
python解释器将所有函数编译为function
类型的特殊对象。在编译期间,它会检查函数创建的所有局部变量(用于垃圾收集等)。这些变量名称保存在函数对象中。因为“影子”外部范围变量(创建具有相同名称的变量)是完全合法的,所以分配给的任何变量都没有显式声明为global
(或python3中的nonlocal
)被假定为局部变量。
执行该函数时,解释器必须查找它遇到的每个变量引用。如果在编译期间发现变量是本地变量,则在函数f_locals字典中搜索它。如果尚未分配,则会引发您遇到的异常。如果变量未在函数范围内分配,因此不是其本地的一部分,则会在周围的范围中查找 - 如果在那里找不到,则会引发类似的异常。
答案 1 :(得分:7)
访问变量与分配变量不同。
您对全局变量有类似的情况。您可以在任何函数中访问它们,但如果您尝试在没有global
语句的情况下分配它们,它将在本地上下文中重新声明它。
不幸的是,对于本地函数,没有等效的global
语句,但您可以通过替换
cache=[v]
使用:
cache[:] = [v]
答案 2 :(得分:3)
由于Python看到cache=[v]
- 赋值给cache
,因此它将其视为局部变量。所以错误是非常合理的 - 在cache
语句中使用之前没有定义局部变量if
。
你可能想把它写成:
def get_match():
cache=[]
def match(v):
if cache:
return cache
cache.append(v)
return cache
return match
m = get_match()
m(1)
强烈推荐的读数:Execution Model - Naming and binding和PEP 227 - Statically Nested Scopes
答案 3 :(得分:0)
替换
cache=[]
def match(v):
与
def match(v,cache=[])
说明:您的代码将cache
声明为get_match
的变量,返回的match(v)
一无所知(由于以下分配)。但是,您希望cache
成为match
命名空间的一部分。
我知道这种方式“恶意”用户可以重新定义缓存,但这是他们自己的错误。 如果这个 是一个问题,那么替代方案是:
def match(v):
try:
if cache:
return cache
except NameError:
cache = []
...
(见here)