2020年4月7日

[Python] Dangerous default value

最近跑 pylint 時偶然發現了一個 warning 叫 "Dangerous default value as argument",細追之後才發現一個陷阱


先看個範例,看看甚麼情況下會有這個 warning:

def foo(k, v, arg={}):
    arg[k] = v
    print(arg)

foo('a', 1)
foo('b', 2)
foo('c', 3, {'A': 1})

拿這個範例去跑 pylint (python 3.6.2) 會得到這個訊息:
W0102: Dangerous default value {} as argument (dangerous-default-value)
問題就是出在 foo 這個函數的參數 arg 有預設值 {},而 pylint 說用 {} 當預設值是很危險的

怎麼個危險法? 上面這例子的 output 是

{'a': 1}
{'a': 1, 'b': 2}
{'A': 1, 'c': 3}

可以注意第二行,前一次 call foo('a', 1) 時對參數 arg 的修改被保留下來了,當然如果你有傳別的 dictionary 進去的話,foo 裡面修改是針對傳進去的 dictionary。從這邊可以推斷 default argument 會一直保留,每次 function call 只要是沒有給值要使用 default argument 時,python 會拿同一個 object 給你

就結論來說,這種情況有兩種處理方案:
  1. 如果你不會修改這類有 default argument 的 parameter 的值,那這個 warning 可忽略
  2. default argument 改用 None

沒有留言:

張貼留言