寫在之前
Python 提供了很多讓使用者覺得舒服至極的功能特性,但是隨著不斷的深入學(xué)習(xí)和使用 Python,我發(fā)現(xiàn)其中存在著許多玄學(xué)的輸出與之前預(yù)想的結(jié)果大相徑庭,這個(gè)對(duì)于初學(xué)者來說難以理解,但是在理解它們以后又會(huì)覺得是這么的有意思,所以我準(zhǔn)備了這個(gè)「有趣的 Python 特性」系列,寫一些我碰到或看到的一些你所不知道的「奇葩」,這里面會(huì)涉及到在 Python2 和 Python3 中的異同,希望大家能從學(xué)習(xí)的過程中體會(huì)到真正的樂趣。
當(dāng)心默認(rèn)可變參數(shù)
首先我們先來看一個(gè)例子:
def test_func(default_arg=[]):
default_arg.append('rocky0429')
return default_arg
我們都知道如果調(diào)用上述函數(shù) 1 次以后所出現(xiàn)的結(jié)果:
>>> test_func()
['rocky0429']
那么如果調(diào)用 2 次,3 次呢?你可以先自己思考一下再繼續(xù)看下面的結(jié)果:
>>> test_func()
['rocky0429', 'rocky0429']
>>> test_func()
['rocky0429', 'rocky0429', 'rocky0429']
咦?明明我們的函數(shù)里明明對(duì)默認(rèn)的可變參數(shù)賦值了,為什么第 1 次調(diào)用是初始化的狀態(tài),第 2 次,第 3 次出現(xiàn)的結(jié)果就不是我們想要的了呢?先別急,我們?cè)倮^續(xù)看下面的調(diào)用:
>>> test_func([])
['rocky0429']
>>> test_func()
['rocky0429', 'rocky0429', 'rocky0429', 'rocky0429']
是不是更懵了?
其實(shí)出現(xiàn)這樣的結(jié)果是因?yàn)?Python 中函數(shù)的默認(rèn)可變參數(shù)并不是每次調(diào)用該函數(shù)時(shí)都會(huì)初始化。相反,它們會(huì)使用最近分配的值作為默認(rèn)值。在上述的 test_func([]) 的結(jié)果不同是因?yàn)?,?dāng)我們將明確的 [] 作為參數(shù)傳遞給 test_func() 的時(shí)候,就不會(huì)使用 test_func 的默認(rèn)值,所以函數(shù)返回的是我們期望的值。
在自定義函數(shù)的特殊屬性中,有個(gè)「 defaults」 會(huì)以元組的形式返回函數(shù)的默認(rèn)參數(shù)。下面我們就用「 defaults」來演示一下,以便讓大家有個(gè)更直觀的感覺:
>>> test_func.__defaults__ #還未調(diào)用
([],)
>>> test_func() # 第 1 次
['rocky0429']
>>> test_func.__defaults__ # 第 2 次的默認(rèn)值
(['rocky0429'],)
>>> test_func() # 第 2 次
['rocky0429', 'rocky0429']
>>> test_func.__defaults__ # 第 2 次的默認(rèn)值
(['rocky0429', 'rocky0429'],)
>>> test_func([]) # 輸入確定的 []
['rocky0429']
>>> test_func.__defaults__ # 此時(shí)的默認(rèn)值
(['rocky0429', 'rocky0429'],)
那么上面那種情況該如何避免呢?畢竟我們還是希望在每次調(diào)用函數(shù)的時(shí)候都是初始化的狀態(tài)的?這個(gè)也很簡(jiǎn)單,就是將 None 指定為參數(shù)的默認(rèn)值,然后檢查是否有值傳給對(duì)應(yīng)的參數(shù)。所以對(duì)于文章開始的那個(gè)例子,我們可以改成如下的形式:
def test_func(default_arg=None):
if not default_arg:
default_arg = []
default_arg.append('rocky0429')
return default_arg
以上,完美解決。
寫在之后
更多內(nèi)容,歡迎關(guān)注公眾號(hào)「Python空間」,期待和你的交流。
|