add by zhj: 文章寫的很好,其實只要默認參數在函數中只讀不寫,那默認值就不會被修改,可變類型作默認參數就不會有問題app
方法二中,當result is None時,修改result的指向,再也不指向默認參數對象,而是賦值一個新的對象。以下,能夠看到,result的id變化了函數
In [4]: def f(p=None, q=[]): ...: print id(p), id(q) ...: if p is None: ...: p = [] ...: print id(p) ...: In [5]: f() 9568656 140309648126608 140309648094632 In [6]: f() 9568656 140309648126608 140309648074944
原文:https://blog.csdn.net/sinat_38068807/article/details/85677419測試
說明:默認參數值在函數被定義時已經計算出來,而不是在程序運行時。Python 程spa
序員常常犯的一個錯誤是把可變的數據類型(例如列表或者字典)看成默認參數值.net
在下面的例子中,函數 buggy() 在每次調用時,添加參數 arg 到一個空的列表 result ,然
後打印輸出一個單值列表。可是存在一個問題:只有在第一次調用時列表是空的,第二次
調用時就會存在以前調用的返回值code
def buggy(arg, result=[]): result.append(arg) print(result) print('--------1--------') buggy('a') print('--------2--------') buggy('b') # 指望獲得 ['b']
執行結果:對象
--------1-------- ['a'] --------2-------- ['a', 'b']
1.默認參數值在函數被定義時已經計算出來,而不是在程序運行時blog
2.只要函數調用時沒有傳遞新的列表來覆蓋默認參數列表,函數就會使用定義時的那個列表,而且操做依次疊加get
3.上面兩次調用中,都沒有傳遞新的列表,程序會調用定義函數時保存的默認參數,並在上一次的基礎上進行操做疊加,即:列表在append的時候會在 result原來的基礎上append追加值,因此會產生以上結果.class
咱們經過打印列表的ID進行辨識來看看:
def buggy(arg, result=[]): print(id(result)) result.append(arg) print(result) print('--------1--------') buggy('a') print('--------2--------') buggy('b') # expect ['b']
結果:
--------1-------- 12205768 ['a'] --------2-------- 12205768 ['a', 'b']
咱們會發現ID值是相同的;
說明兩次執行時使用的都是開始定義函數時的默認參數 ,進行了操做疊加
4.下面咱們傳遞新的列表看看:
def buggy(arg, result=[]): print(id(result)) result.append(arg) print(result) print('--------1--------') buggy('a') print('--------2--------') buggy('b', []) # 傳遞了新的列表
結果:
--------1-------- 18497224 ['a'] --------2-------- 18504648 ['b']
發現,列表id不一樣,而且獲得了咱們指望的值
方法1
# 若是寫成下面的樣子就會解決剛纔的問題: def works(arg): result = [] result.append(arg) print(result) works('a') works('b')
結果:
['a'] ['b']
方法2:
# 這樣的修改也爲了代表是第一次調用跳過一些操做: def nonbuggy(arg, result=None): if result is None: result = [] result.append(arg) print(result) nonbuggy('a') nonbuggy('b')
結果:
['a'] ['b']