學過函數的人必定據說過函數的默認參數,關於函數的默認參數,請看如下的例子: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/