網站首頁 編程語言 正文
函數的默認參數請勿定義可變類型
經常會看到這樣一句代碼警告:
Default argument value is mutable
意思是告訴我們函數的定義中,使用可變類型做默認參數。
那為什么會有這個警告呢?
可變類型和不可變類型
- 可變類型(mutable):列表,字典
- 不可變類型(unmutable):數字,字符串,元組
定義可變類型會有什么問題?
def fun(a=[]): ? ? a.append(1) ? ? print(a) if __name__ == "__main__": ? ? fun() ? ? fun() >>> [1] ?? ?[1, 1]
可以發現,默認參數定義可變類型之后,在第二次乃至更多次地調用同一個函數時,默認參數仿佛失去了效果。
此時,在需要重復調用同一個函數的場景中,就非常容易導致問題,并且該問題不易察覺。在debug的時候就會表現成明明沒有參數傳進來,但是函數參數會有值,并且執行了不應該執行的操作。
導致的原因
我的理解:
我們定義的函數本身是一個function的實例化對象,每當我們進行函數的定義時,就是創建了一個function的實例化對象,而默認參數就是其屬性。
在沒有傳入參數,以默認參數形式調用,并且改變了函數對象的屬性值時,改變的屬性值被保存下來,當第二次調用同一個對象時,屬性值已經發生了改變。
type(fun) >>> function
解決方法
def fun(a=None): ?? ?if a is None: ?? ?a = [] ? ? a.append(1) ? ? print(a) if __name__ == "__main__": ? ? fun() ? ? fun() >>> [1] ?? ?[1]
關于可變類型作為默認參數時的注意點
請先看代碼,看看代碼的輸出是否和你想的一樣。
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'])
關于上述代碼,標準解釋是:帶有默認參數的表達式在函數被定義的時候被計算,不是在調用的時候計算。
我覺得通俗的解釋是:當不傳默認值的時候,無論調用多少次該函數,在函數體內部使用的一直都是那個默認的“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 是
其實以上類型都已經說明問題了,但是寫個文章不容易,我決定用元祖包列表,看看修改這個列表中的數據會怎樣。
實際上是不用測試的,最終打印出來的數據一定是類似**“可變類型時的操作”**時的輸出的。
為什么?因為我沒有修改元祖本身,修改的是其可變類型列表啊。
不能扯遠了,不然扯到深拷貝,淺拷貝了。
測試:元祖包個列表來
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(())你就知道了。 ?? ?# 好吧,其實是因為元祖是可讀不可寫的。它能切片、遍歷就已經很不錯了。。。。。 ?? ?return t t1=e("我") t2=e("a",([],)) t3=e("是") print(t1,"\n",t2,"\n",t3) # 輸出: # (['我', '是'],)? # (['a'],)? # (['我', '是'],)
小結一下
家里停電了,所以我來到了網吧,這篇文章是在網吧寫的,用的是python3的在線編輯器,有的地方編碼(比如命名-。-)或者表述的不好請多多見諒。
關于集合,我就不做測試了,集合一般用于去重和關系運算,它是無序,不重復,可變類型。?
原文鏈接:https://blog.csdn.net/xu136090331/article/details/100056731
相關推薦
- 2024-04-01 使用Vite安裝TailwindCSS
- 2023-02-27 Python使用Crypto庫實現加密解密的示例詳解_python
- 2022-03-18 C語言回溯法解八皇后問題(八皇后算法)_C 語言
- 2021-12-22 Docker部署Microsoft?Sql?Server詳細步驟_docker
- 2022-03-21 windows設置開機自動運行批處理的方法_DOS/BAT
- 2023-07-14 react 如何實現富文本編輯器
- 2022-06-02 關于Python使用turtle庫畫任意圖的問題_python
- 2022-03-17 .NET?6開發TodoList應用引入第三方日志庫_實用技巧
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支