????def?b():
????????x?+=?1
?
????x?=?1
????print?"a:?",?x
????b()
????print?"b:?",?x
?
def?c():
????def?d():
????????x[0]?=?[4]
????x?=?[3]
????print?"c:?",?x[0]
????d()
????print?"d:?",?x[0]
運(yùn)行a()會報(bào)UnboundLocalError: local variable ‘x’ referenced before assignment
但是運(yùn)行c()會正確地顯示3和4。
原因在于原因在于CPython實(shí)現(xiàn)closure的方式和常見的functional language不同,采用了flat closures實(shí)現(xiàn)。
“If a name is bound anywhere within a code block, all uses of the name within the block are treated as references to the current block.”
在第一個(gè)例子中,b函數(shù)x += 1對x進(jìn)行賦值,rebind了這個(gè)對象,于是Python查找x的時(shí)候只會在local environment中搜索,于是就有了UnboundLocalError。
換句話說,如果沒有修改這個(gè)值,比如b中僅僅簡單的輸出了x,程序是可以正常運(yùn)行的,因?yàn)榇藭r(shí)搜索的范圍是nearest enclosing function region。
而d方法并沒有rebind x變量,只是修改了x指向的對象的值而已。如果把賦值語句改成x = [4],那么結(jié)果就和原來不一樣了,因?yàn)榇藭r(shí)發(fā)生了x的rebind。
所以Python中的closure可以理解為是只讀的。
另外第二個(gè)例子也是這篇文章中提到的一種workaround:把要通過inner function修改的變量包裝到數(shù)組里,然后在inner function中訪問這個(gè)數(shù)組。
至于為什么Python中enclosed function不能修改enclosing function的binding,文中提到了主要原因還是在于Guido反對這么做。因?yàn)檫@樣會導(dǎo)致本應(yīng)該作為類的實(shí)例保存的對象被聲明了本地變量。
參考網(wǎng)站:http://www.python.org/dev/peps/pep-0227/