理解 Python 闭包,感到困惑的点:
>>> x = 1
>>> def f():
y = []
def ff():
y += [11] # 问题应该是出现在变量名的使用上
return y
return ff
>>> l = f()
>>> l()
Traceback (most recent call last):
File "<pyshell#144>", line 1, in <module>
l()
File "<pyshell#142>", line 4, in ff
y += [11]
UnboundLocalError: local variable 'y' referenced before assignment
# 抛出未绑定的局部变量异常,为什么呢? OK,换一种写法:
>>> def f():
y = []
def ff():
y.append(11)
return y
return ff
>>> l = f()
>>> l()
[11]
>>> l()
[11, 11]
>>> l()
[11, 11, 11]
# 一切正常
那上面为什么会抛出UnboundLocalError
异常呢?再换一种写法:
>>> def f():
y = [0]
def ff():
y[0] += 1 # 修改变量的引用,不会抛出异常
return y
return ff
>>> l = f()
>>> l()
[1]
>>> l()
[2]
>>> l()
[3]
总结:
一个函数的调用需要读取或修改该函数外部作用域的变量时:
1. 直接读取该变量,(变量解析的 LEGB 法则,即标识符的搜索顺序:Local -> Enclosing(直接外围空间) -> Global -> Builtin),在任何一层找到该变量即停止搜索,若直到 Builtin 层仍未找到该变量则抛出NameError
异常;
2. 若需要修改变量,确保操作该变量的引用,否则抛出UnboundLocalError
异常。
Lambda 、作用域
lambda 定义了新的作用域,使用 lambda 与 def 定义的函数,在作用域方面没有本质的不同。都是在函数调用时按照 LEGB 顺序解析变量。
>>> x = 5
>>> def f():
... y = 10
... bar = lambda : x + y
... print bar() # bar() 被调用使按 LEGB 顺序解析变量
... y = 0
... print bar() # 同上
>>>f()
15
5