python默認參數陷阱


陷阱?

學過函數的人一定聽說過函數的默認參數,關於函數的默認參數,請看以下的例子:

def extendList(val, lst=[]):
    lst.append(val)
    return lst
list1 = extendList(10)
list2 = extendList(123, [])
print('list1 = %s' % list1)
print('list2 = %s' % list2)

打印的結果是 現在,我們將代碼再添加一處,來看看最后的結果是什么:

def extendList(val, lst=[]):
    lst.append(val)
    return lst
list1 = extendList(10)
list2 = extendList(123, [])
list3 = extendList('a')
print('list1=%s' % list1)
print('list2=%s' % list2)
print('list3=%s' % list3)

當list1處調用函數時,10被加入了列表;list2處調用函數,123被加入到了新傳入的列表中;最后到list3調用函數,應該將‘a’繼續加入到列表中返回。因此得到的輸出應該是:

# list1 = [10]
# list2 = [233]
# list3 = ['a']

陷阱!

然而,實際的打印結果變成了:

陷阱之所以稱之為陷阱,代表我們不能以普通的思維來看待它,通過查閱資料,得到以下的一句解釋:

A new list is created once when the function is defined, and the same list is used in each successive call.

在定義函數時,Python的默認參數會被計算一次,而不是每次調用函數時(比如Ruby)。這意味着如果你使用一個可變的默認參數並對其進行改變,那么你將會直接修改該對象,該影響將一直延續到未來關於該函數的調用(在默認參數沒有被重新賦其他值的情況下)。

眾所周知,Python變量存儲的是變量和值的引用關系,即實際變量對應一個內存地址這意味着Python函數總是通過地址傳遞(傳遞參數)工作。調用函數時,不會參數值復制到函數占位符。相反,我們將占位符指向變量本身。這有一個非常重要的結果:我們可以從函數內部更改變量的值。

如何避開陷阱?

None通常是一個不錯的選擇:

def extendList(val, lst = None):
    if not lst:
        lst = []
    lst.append(val)
    return lst

 有時您可以專門利用此陷阱來維護函數調用之間的狀態。這通常在編寫緩存函數時完成。

 

 

參考資料:https://docs.python-guide.org/writing/gotchas/

http://blog.thedigitalcatonline.com/blog/2015/02/11/default-arguments-in-python/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM