Python函數學習筆記
來源:互聯網
上載者:User
局部名字靜態檢測
Python探測局部範圍的時候:是在python編譯代碼時檢測,而不是通過他們在運行時的賦值。
正常的情況下,沒在函數中複製的名字將在包含它的模組中尋找:
>>> x=99
>>> def selector():
... print x
...
>>> selector()
99
但是:
>>> def selector():
... print x
... x=100
...
>>> selector()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in selector
UnboundLocalError: local variable 'x' referenced before assignment
會得到未定義名字的錯誤。
當 互動式輸入或從一個模組中匯入時,python讀取並編譯這段代碼,當編譯時間python查看x的賦值,並決定在函數中任何地方x都將是個局部名字。到後 來函數真的運行,print執行時,賦值還沒有發生,python會說你正在使用一個未定義的名字。根據他的名字規則,應該是局部的x在賦值前被使用了。
解決辦法:
如果你想列印全域x,你應該在global語句中聲明:(這意味著該賦值也改變全域x,而不是局部x)
>>> def selector():
... global x
... print x
... x=88
...
>>> selector()
99
如果你想列印出全域賦值,在設定一個局部的,匯入包含它的模組並用限定得到這個全域的版本:
>>> x=99
>>> def selector():
... import __main__
... print __main__.x
... x=88
... print x
...
>>> selector()
99
88
限定(.x部分)從一個名字空間對象中得到一個值。互動環境的名字空間是一個叫做__main__的模組。
嵌套函數可以嵌套範圍(在新版本中和老版本中不同)
>>> def outer(x):
... def inner(i):
... print i,
... if i: inner(i-1)
... inner(x)
...
>>> outer(3)
3 2 1 0
使用預設值儲存引用
>>> def outer(x):
... def inner(i,self=inner):
... print i,
... if i:self(i-1)
... inner(x)
...
>>> outer(3)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in outer
UnboundLocalError: local variable 'inner' referenced before assignment
解決原則:最簡單的方式總是最正確的方式
>>> def inner(i):
... print i,
... if i:inner(i-1)
...
>>> def outer(x):
... inner(x)
...
>>> outer(3)
3 2 1 0
預設的可變對象
>>> def saver(x=[]):
... x.append(1)
... print x
...
>>> saver([2])
[2, 1]
>>> saver()
[1]
>>> saver()
[1, 1]
>>> saver()
[1, 1, 1]
問題是,這裡只有一個列表對象——def執行時產生的一個。在每一次函數被調用時,你不會得到新的列表對象,而是原列表對象的增長。
解決辦法:如果那不是你想要的行為,簡單的移動預設值到函數體中。只要代碼裡的值在每一次函數運行時都執行,你每次將得到一個新的對象:
>>> def saver(x=None):
... if x is None:
... x=[]
... x.append(1)
... print x
...
>>> saver([2])
[2, 1]
>>> saver()
[1]
>>> saver()
[1]
>>> saver()
[1]
上 面的if語句幾乎可以被賦值x=x or []代替,因為python的or將返回他的操作對象中的一個:如果沒有參數被傳遞,x預設為None,所以or在右側返回一個產生的空列表。但這不完全 一樣,當傳遞的是空列表時,函數將擴充並返回一個新產生的列表,而不是向前面的版本那樣擴充並返回一個被傳遞的列表(運算式變成[] or [],這將計算出新的列表)