def foo(): a = 1 def bar(): a = a + 1 # print a + 1 # b = a + 1 # a = 1 print id(a) bar() print a, id(a)
在Python2.x上運行這個函數會報UnboundLocalError: local variable 'a' referenced before assignment即本地變量在引用前未定義,如何來理解這個錯誤呢?PEP 227里面介紹到,Python解析器在搜索一個變量的定義時是根據如下三級規則來查找的:
The Python 2.0 definition specifies exactly three namespaces to check for each name — the local namespace, the global namespace, and the builtin namespace.
這里的local實際上可能還有多級,上面的代碼就是一個例子,下面通過對代碼做些簡單的修改來一步步理解這里面的規律:
要解決這個問題,在Python2.x里主要有兩個方案:
用別名替代比如b = a + 1,內部函數bar內只引用外部函數foo里的a。
將foo里的a設成一個容器,如list
def foo(): a = [1, ] def bar(): a[0] = a[0] + 1 bar() print a[0]
當然這有些時候還是很不方便,因此在Python3.x中引入了一個nonloacal的關鍵字來解決這個問題,只要在a = a + 1前加一句nonloacal a即可,即顯式的指定a不是內部函數bar內的本地變量,這樣就可以在bar內正常的使用和再賦值外部函數foo內的變量a了。
在搜索Python閉包相關的材料中,我在StackOverflow上發現一個有趣的有關Python閉包的問題,有興趣的可以思考思考做做看,結果應該是什么?你預期的結果是什么,若不一致,如果要得到你預期的結果應該怎么改?
flist = [] for i in xrange(3): def func(x): return x * i flist.append(func) for f in flist: print f(2)