python默認參數陷阱

陷阱?

學過函數的人必定據說過函數的默認參數,關於函數的默認參數,請看如下的例子:python

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

打印的結果是 如今,咱們將代碼再添加一處,來看看最後的結果是什麼:git

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']

陷阱!

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

陷阱之因此稱之爲陷阱,表明咱們不能以普通的思惟來看待它,經過查閱資料,獲得如下的一句解釋:ide

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

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

衆所周知,Python變量存儲的是變量和值的引用關係,即實際變量對應一個內存地址這意味着Python函數老是經過地址傳遞(傳遞參數)工做。調用函數時,不會參數值複製到函數佔位符。相反,咱們將佔位符指向變量自己。這有一個很是重要的結果:咱們能夠從函數內部更改變量的值。spa

如何避開陷阱?

None一般是一個不錯的選擇:code

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/

相關文章
相關標籤/搜索