網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
函數(shù)的默認(rèn)參數(shù)請(qǐng)勿定義可變類(lèi)型
經(jīng)常會(huì)看到這樣一句代碼警告:
Default argument value is mutable
意思是告訴我們函數(shù)的定義中,使用可變類(lèi)型做默認(rèn)參數(shù)。
那為什么會(huì)有這個(gè)警告呢?
可變類(lèi)型和不可變類(lèi)型
- 可變類(lèi)型(mutable):列表,字典
- 不可變類(lèi)型(unmutable):數(shù)字,字符串,元組
定義可變類(lèi)型會(huì)有什么問(wèn)題?
def fun(a=[]): ? ? a.append(1) ? ? print(a) if __name__ == "__main__": ? ? fun() ? ? fun() >>> [1] ?? ?[1, 1]
可以發(fā)現(xiàn),默認(rèn)參數(shù)定義可變類(lèi)型之后,在第二次乃至更多次地調(diào)用同一個(gè)函數(shù)時(shí),默認(rèn)參數(shù)仿佛失去了效果。
此時(shí),在需要重復(fù)調(diào)用同一個(gè)函數(shù)的場(chǎng)景中,就非常容易導(dǎo)致問(wèn)題,并且該問(wèn)題不易察覺(jué)。在debug的時(shí)候就會(huì)表現(xiàn)成明明沒(méi)有參數(shù)傳進(jìn)來(lái),但是函數(shù)參數(shù)會(huì)有值,并且執(zhí)行了不應(yīng)該執(zhí)行的操作。
導(dǎo)致的原因
我的理解:
我們定義的函數(shù)本身是一個(gè)function的實(shí)例化對(duì)象,每當(dāng)我們進(jìn)行函數(shù)的定義時(shí),就是創(chuàng)建了一個(gè)function的實(shí)例化對(duì)象,而默認(rèn)參數(shù)就是其屬性。
在沒(méi)有傳入?yún)?shù),以默認(rèn)參數(shù)形式調(diào)用,并且改變了函數(shù)對(duì)象的屬性值時(shí),改變的屬性值被保存下來(lái),當(dāng)?shù)诙握{(diào)用同一個(gè)對(duì)象時(shí),屬性值已經(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)于可變類(lèi)型作為默認(rèn)參數(shù)時(shí)的注意點(diǎn)
請(qǐng)先看代碼,看看代碼的輸出是否和你想的一樣。
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)于上述代碼,標(biāo)準(zhǔn)解釋是:帶有默認(rèn)參數(shù)的表達(dá)式在函數(shù)被定義的時(shí)候被計(jì)算,不是在調(diào)用的時(shí)候計(jì)算。
我覺(jué)得通俗的解釋是:當(dāng)不傳默認(rèn)值的時(shí)候,無(wú)論調(diào)用多少次該函數(shù),在函數(shù)體內(nèi)部使用的一直都是那個(gè)默認(rèn)的“l(fā)”,而這個(gè)默認(rèn)的“l(fā)”又是可變類(lèi)型,所以,它的改變會(huì)影響所有指向它的變量,也就是l1和l3。
為了使以上兩點(diǎn)的觀點(diǎn)更加站的住腳,我進(jìn)行以下幾個(gè)測(cè)試。
測(cè)試:將可變類(lèi)型列表?yè)Q為字典
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})
測(cè)試:來(lái)個(gè)不可變類(lèi)型字符串
def e(v,s=""): ?? ?s = s+v ?? ?return s s1=e("我") s2=e("a","") s3=e("是") print(s1,s2,s3) # 輸出: 我 a 是
其實(shí)以上類(lèi)型都已經(jīng)說(shuō)明問(wèn)題了,但是寫(xiě)個(gè)文章不容易,我決定用元祖包列表,看看修改這個(gè)列表中的數(shù)據(jù)會(huì)怎樣。
實(shí)際上是不用測(cè)試的,最終打印出來(lái)的數(shù)據(jù)一定是類(lèi)似**“可變類(lèi)型時(shí)的操作”**時(shí)的輸出的。
為什么?因?yàn)槲覜](méi)有修改元祖本身,修改的是其可變類(lèi)型列表啊。
不能扯遠(yuǎn)了,不然扯到深拷貝,淺拷貝了。
測(cè)試:元祖包個(gè)列表來(lái)
def e(v,t=([],)): ?# 傳遞有元素的元祖的時(shí)候要記得帶逗號(hào)哦。 ?? ? ?? ?t[0].append(v) ?? ?# t = t[0].append(v) ? ? 要知道t[0].append(v)是沒(méi)有返回值的,t會(huì)指向None,如果這樣返回,外部打印的全部為None,所以不可以這樣返回。 ?? ?# 而且 如果你想 t[0]= t[0].append(v) 也是不行的,為啥?你在ipython中輸入 dir(())你就知道了。 ?? ?# 好吧,其實(shí)是因?yàn)樵媸强勺x不可寫(xiě)的。它能切片、遍歷就已經(jīng)很不錯(cuò)了。。。。。 ?? ?return t t1=e("我") t2=e("a",([],)) t3=e("是") print(t1,"\n",t2,"\n",t3) # 輸出: # (['我', '是'],)? # (['a'],)? # (['我', '是'],)
小結(jié)一下
家里停電了,所以我來(lái)到了網(wǎng)吧,這篇文章是在網(wǎng)吧寫(xiě)的,用的是python3的在線(xiàn)編輯器,有的地方編碼(比如命名-。-)或者表述的不好請(qǐng)多多見(jiàn)諒。
關(guān)于集合,我就不做測(cè)試了,集合一般用于去重和關(guān)系運(yùn)算,它是無(wú)序,不重復(fù),可變類(lèi)型。?
原文鏈接:https://blog.csdn.net/xu136090331/article/details/100056731
相關(guān)推薦
- 2022-12-04 深入了解Rust的切片使用_Rust語(yǔ)言
- 2022-04-12 C#實(shí)現(xiàn)六大設(shè)計(jì)原則之里氏替換原則_C#教程
- 2022-11-10 rust延遲5秒鎖屏的實(shí)現(xiàn)代碼_相關(guān)技巧
- 2023-08-01 elementui全局給select option添加title屬性
- 2022-11-25 jar包在linux服務(wù)器已經(jīng)運(yùn)行好但是訪問(wèn)不到地址的問(wèn)題及解決方法_Linux
- 2022-01-18 Django解決前端/客戶(hù)端POST失敗提示csrf_tokenxxx的問(wèn)題
- 2023-08-13 微信小程序底部導(dǎo)航欄最多只能顯示五個(gè),解決辦法
- 2022-06-12 使用jquery實(shí)現(xiàn)別踩白塊小游戲的方法實(shí)例_jquery
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支