python函數(shù)的默認參數(shù)請勿定義可變類型詳解
函數(shù)的默認參數(shù)請勿定義可變類型
經(jīng)常會看到這樣一句代碼警告:
Default argument value is mutable
意思是告訴我們函數(shù)的定義中,使用可變類型做默認參數(shù)。
那為什么會有這個警告呢?
可變類型和不可變類型
- 可變類型(mutable):列表,字典
- 不可變類型(unmutable):數(shù)字,字符串,元組
定義可變類型會有什么問題?
def fun(a=[]): ? ? a.append(1) ? ? print(a) if __name__ == "__main__": ? ? fun() ? ? fun() >>> [1] ?? ?[1, 1]
可以發(fā)現(xiàn),默認參數(shù)定義可變類型之后,在第二次乃至更多次地調(diào)用同一個函數(shù)時,默認參數(shù)仿佛失去了效果。
此時,在需要重復(fù)調(diào)用同一個函數(shù)的場景中,就非常容易導(dǎo)致問題,并且該問題不易察覺。在debug的時候就會表現(xiàn)成明明沒有參數(shù)傳進來,但是函數(shù)參數(shù)會有值,并且執(zhí)行了不應(yīng)該執(zhí)行的操作。
導(dǎo)致的原因
我的理解:
我們定義的函數(shù)本身是一個function的實例化對象,每當我們進行函數(shù)的定義時,就是創(chuàng)建了一個function的實例化對象,而默認參數(shù)就是其屬性。
在沒有傳入?yún)?shù),以默認參數(shù)形式調(diào)用,并且改變了函數(shù)對象的屬性值時,改變的屬性值被保存下來,當?shù)诙握{(diào)用同一個對象時,屬性值已經(jīng)發(fā)生了改變。
type(fun) >>> function
解決方法
def fun(a=None): ?? ?if a is None: ?? ?a = [] ? ? a.append(1) ? ? print(a) if __name__ == "__main__": ? ? fun() ? ? fun() >>> [1] ?? ?[1]
關(guān)于可變類型作為默認參數(shù)時的注意點
請先看代碼,看看代碼的輸出是否和你想的一樣。
def e(v,l=[]):
?? ?l.append(v)
?? ?return l
l1=e(10)
l2=e(123,[])
l3=e("a")
print(l1,l2,l3)
# 輸出: ([10, 'a'], [123], [10, 'a'])關(guān)于上述代碼,標準解釋是:帶有默認參數(shù)的表達式在函數(shù)被定義的時候被計算,不是在調(diào)用的時候計算。
我覺得通俗的解釋是:當不傳默認值的時候,無論調(diào)用多少次該函數(shù),在函數(shù)體內(nèi)部使用的一直都是那個默認的“l”,而這個默認的“l”又是可變類型,所以,它的改變會影響所有指向它的變量,也就是l1和l3。
為了使以上兩點的觀點更加站的住腳,我進行以下幾個測試。
測試:將可變類型列表換為字典
def e(k,v,d={}):
?? ?d[k]=v
?? ?return d
d1=e(10,10)
d2=e(123,123,{})
d3=e("a","a")
print(d1,d2,d3)
# 輸出:({'a': 'a', 10: 10}, {123: 123}, {'a': 'a', 10: 10})測試:來個不可變類型字符串
def e(v,s=""):
?? ?s = s+v
?? ?return s
s1=e("我")
s2=e("a","")
s3=e("是")
print(s1,s2,s3)
# 輸出: 我 a 是其實以上類型都已經(jīng)說明問題了,但是寫個文章不容易,我決定用元祖包列表,看看修改這個列表中的數(shù)據(jù)會怎樣。
實際上是不用測試的,最終打印出來的數(shù)據(jù)一定是類似**“可變類型時的操作”**時的輸出的。
為什么?因為我沒有修改元祖本身,修改的是其可變類型列表啊。
不能扯遠了,不然扯到深拷貝,淺拷貝了。
測試:元祖包個列表來
def e(v,t=([],)): ?# 傳遞有元素的元祖的時候要記得帶逗號哦。
?? ?
?? ?t[0].append(v)
?? ?# t = t[0].append(v) ? ? 要知道t[0].append(v)是沒有返回值的,t會指向None,如果這樣返回,外部打印的全部為None,所以不可以這樣返回。
?? ?# 而且 如果你想 t[0]= t[0].append(v) 也是不行的,為啥?你在ipython中輸入 dir(())你就知道了。
?? ?# 好吧,其實是因為元祖是可讀不可寫的。它能切片、遍歷就已經(jīng)很不錯了。。。。。
?? ?return t
t1=e("我")
t2=e("a",([],))
t3=e("是")
print(t1,"\n",t2,"\n",t3)
# 輸出:
# (['我', '是'],)?
# (['a'],)?
# (['我', '是'],)小結(jié)一下
家里停電了,所以我來到了網(wǎng)吧,這篇文章是在網(wǎng)吧寫的,用的是python3的在線編輯器,有的地方編碼(比如命名-。-)或者表述的不好請多多見諒。
關(guān)于集合,我就不做測試了,集合一般用于去重和關(guān)系運算,它是無序,不重復(fù),可變類型。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- python函數(shù)默認參數(shù)使用避坑指南
- Python中的函數(shù)參數(shù)(位置參數(shù)、默認參數(shù)、可變參數(shù))
- Python如何定義有默認參數(shù)的函數(shù)
- Python新手學習函數(shù)默認參數(shù)設(shè)置
- Python函數(shù)默認參數(shù)常見問題及解決方案
- Python函數(shù)的默認參數(shù)設(shè)計示例詳解
- Python中函數(shù)及默認參數(shù)的定義與調(diào)用操作實例分析
- Python進階-函數(shù)默認參數(shù)(詳解)
- 深入講解Python函數(shù)中參數(shù)的使用及默認參數(shù)的陷阱
- 詳細介紹Python函數(shù)中的默認參數(shù)
- Python函數(shù)默認參數(shù)設(shè)置的具體方法
相關(guān)文章
基于python+selenium自動健康打卡的實現(xiàn)代碼
這篇文章主要介紹了基于python+selenium自動健康打卡,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01
python判斷列表的連續(xù)數(shù)字范圍并分塊的方法
今天小編就為大家分享一篇python判斷列表的連續(xù)數(shù)字范圍并分塊的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11
python?(pyqt)?表格顯示圖片的實現(xiàn)方式
這篇文章主要介紹了python?(pyqt)?表格顯示圖片的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
Django在admin后臺集成TinyMCE富文本編輯器的例子
今天小編就為大家分享一篇Django在admin后臺集成TinyMCE富文本編輯器的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08

