Python3中加入了新的關鍵字nonlocal,當在一個嵌套的函數中對變量申明為nonlocal時,就明確表示這個變量是外部函數中定義的變量。也許會有這么一個問題:按照python的LEGB原則,在函數本地作用域找不到變量的情況下,解釋器會自動在外層函數尋找,nonlocal關鍵字豈不是顯得多余? 是的,當一個函數在本地作用域找不到變量申明時會向外層函數尋找,這在函數閉包中很常見。如下:
1 def test(num1): 2 def add(num2): 3 return num1 + num2 4 return add 5 6 a = test(1) 7 b = test(2) 8 print(a(1)) 9 print(b(1))
輸出為:
2 3
但是在本地作用域中使用的變量后,還想對此變量進行更改賦值就會報錯。如下:
def test(): count = 1 def add(): print(count) count += 1 return add a = test() a()
輸出為:
--------------------------------------------------------------------------- UnboundLocalError Traceback (most recent call last) <ipython-input-6-24732f13d2b6> in <module>() 7 8 a = test() ----> 9 a() <ipython-input-6-24732f13d2b6> in add() 2 count = 1 3 def add(): ----> 4 print(count) 5 count += 1 6 return add UnboundLocalError: local variable 'count' referenced before assignment
在上面代碼中,如果在使用count前面加上關鍵字nonlocal申明就可解決這個問題:
def add(): count = 1 def fun(): nonlocal count print(count) count += 1 return fun a = add() a() a()
輸出為:
1 2
上面代碼完美地解決了函數嵌套調用外部變量的問題;另外,如果從另一個角度來看我們給此函數增加了記錄函數狀態的功能。當然,這也可以通過申明全局變量來實現增加函數狀態的功能。當這樣會出現以下問題:
1. 每次調用函數時,都得在全局作用域申明變量。別人調用函數時還得查看函數內部代碼。
2. 當函數在多個地方被調用並且同時記錄着很多狀態時,會造成非常地混亂。
使用nonlocal的好處是,在為函數添加狀態時不用額外地添加全局變量,因此可以大量地調用此函數並同時記錄着多個函數狀態,每個函數都是獨立、獨特的。針對此項功能其實還個一個方法,就是使用類,通過定義__call__可實現在一個實例上直接像函數一樣調用。