python函數的閉包問題(內嵌函數)
>>> def func1():
... print ('func1 running...')
... def func2():
... print ('func2 running...')
... func2()
...
>>> func1()
func1 running...
func2 running...
內部函數func2
作用域都在外部函數func1
作用域之內
如果試圖在外部函數的外部調用內部函數將會報錯!
>>> func2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'func2' is not defined
關於python的閉包問題
如果試圖在一個內部函數裏對外部作用域(不包括外部函數的外部作用域)的變量進行引用,內部函數就會被認爲是閉包。
>>> def FuncX(x):
... def FuncY(y):
... return x*y
... return FuncY
對於FuncY
函數來說,對在FuncX
函數的整個作用域(FuncY
函數的非全局作用域的外部作用)的變量x
進行引用,自此就可以說FuncY
函數就是所謂的閉包。
>>> f = FuncX(8)
>>> f
<function FuncY at 0x7f3a436fc2a8>
>>> type(f)
<type 'function'>
>>> f(10)
80
>>> FuncX(7)(8)
56
由於閉包本身是基於內部函數這一概念而來,所以不能在外部函數的外部作用域對內部函數進行調用。
>>> FuncY(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'FuncY' is not defined
既然是基於內部函數這一概念而來,自然對於內部函數來說對引用外部函數作用域內的變量進行修改,將會啓動解釋器的屏蔽機制。
>>> def Func1():
... x = 233
... def Func2():
... x *=x
... return x
... return Func2()
...
>>> Func1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in Func1
File "<stdin>", line 4, in Func2
UnboundLocalError: local variable 'x' referenced before assignment
x*=x
的左值此時是內部函數作用域裏的變量,此時試圖將沒有定義的數據進行平方操作,因此報錯!
>>> def Func1():
... x = 233
... def Func2():
... x = 321
... return x
... return Func2()
...
>>> Func1()
321
內部函數創建x變量並且屏蔽外部函數作用域內的x變量!
python3之前的解決辦法
應用容器類型(list
,tuple
之類的)存放外部函數作用域的變量從而不會被屏蔽機制屏蔽掉,因爲容器類型不是存放在棧裏面!
>>> def Func1():
... x = [233]
... def Func2():
... x[0] *= x[0]
... return x[0]
... return Func2()
...
>>> Func1()
54289
python3之後的解決辦法:nonlocal關鍵字
>>> def Func1():
... x = 233
... def Func2():
... nonlocal x
... x *= x
... return x
... return Func2()
...
>>> Func1()
54289