Python編程中運用閉包時所需要注意的一些地方
寫下這篇博客,起源于Tornado郵件群組的這個問題how to use outer variable in inner method,這里面老外的回答很有參考價值,關(guān)鍵點基本都說到了。我在這里用一些有趣的例子來做些解析,簡要的闡述下Python的閉包規(guī)則,首先看一個經(jīng)典的例子:
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上運行這個函數(shù)會報UnboundLocalError: local variable 'a' referenced before assignment即本地變量在引用前未定義,如何來理解這個錯誤呢?PEP 227里面介紹到,Python解析器在搜索一個變量的定義時是根據(jù)如下三級規(guī)則來查找的:
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實際上可能還有多級,上面的代碼就是一個例子,下面通過對代碼做些簡單的修改來一步步理解這里面的規(guī)律:
- 如果將a = a + 1這句換成print a + 1或者b = a + 1,是不會有問題的,即在內(nèi)部函數(shù)bar內(nèi),外部函數(shù)foo里的a實際是可見的,可以引用。
- 將a = a + 1換成 a = 1也是沒有問題的,但是如果你將兩處出現(xiàn)的a的id打印出來你會發(fā)現(xiàn),其實這兩個a不是一回事,在內(nèi)部函數(shù)bar里面,本地的a = 1定義了在bar函數(shù)范圍內(nèi)的新的一個局部變量,因為名字和外部函數(shù)foo里面的變量a名字相同,導(dǎo)致外部函數(shù)foo里的a在內(nèi)部函數(shù)bar里實際已不可見。
- 再來說a = a + 1出錯是怎么回事,首先a = xxx這種形式,Python解析器認(rèn)為要在內(nèi)部函數(shù)bar內(nèi)創(chuàng)建一個新的局部變量a,同時外部函數(shù)foo里的a在bar里已不可見,而解析器對接下來對右邊的a + 1的解析就是用本地的變量a加1,而這時左邊的a即本地的變量a還沒有創(chuàng)建(等右邊賦值呢),因此就這就產(chǎn)生了一個是雞生蛋還是蛋生雞的問題,導(dǎo)致了上面說的UnboundLocalError的錯誤。
要解決這個問題,在Python2.x里主要有兩個方案:
用別名替代比如b = a + 1,內(nèi)部函數(shù)bar內(nèi)只引用外部函數(shù)foo里的a。
將foo里的a設(shè)成一個容器,如list
def foo(): a = [1, ] def bar(): a[0] = a[0] + 1 bar() print a[0]
當(dāng)然這有些時候還是很不方便,因此在Python3.x中引入了一個nonloacal的關(guān)鍵字來解決這個問題,只要在a = a + 1前加一句nonloacal a即可,即顯式的指定a不是內(nèi)部函數(shù)bar內(nèi)的本地變量,這樣就可以在bar內(nèi)正常的使用和再賦值外部函數(shù)foo內(nèi)的變量a了。
在搜索Python閉包相關(guān)的材料中,我在StackOverflow上發(fā)現(xiàn)一個有趣的有關(guān)Python閉包的問題,有興趣的可以思考思考做做看,結(jié)果應(yīng)該是什么?你預(yù)期的結(jié)果是什么,若不一致,如果要得到你預(yù)期的結(jié)果應(yīng)該怎么改?
flist = [] for i in xrange(3): def func(x): return x * i flist.append(func) for f in flist: print f(2)
相關(guān)文章
在Python中調(diào)用Ping命令,批量IP的方法
今天小編就為大家分享一篇在Python中調(diào)用Ping命令,批量IP的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01利用python3篩選excel中特定的行(行值滿足某個條件/行值屬于某個集合)
這篇文章主要給大家介紹了關(guān)于利用python3篩選excel中特定的行(行值滿足某個條件/行值屬于某個集合)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Python 如何將integer轉(zhuǎn)化為羅馬數(shù)(3999以內(nèi))
這篇文章主要介紹了Python 將integer轉(zhuǎn)化為羅馬數(shù)(3999以內(nèi))的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Python實現(xiàn)一鍵整理百度云盤中重復(fù)無用文件
有沒有頭疼過百度云盤都要塞滿了,可是又沒有工具能剔除大量重復(fù)無用的文件?這里教你一個用Python實現(xiàn)的簡單方法,通過整理目錄的方式來處理我們云盤中無用的文件吧2022-08-08