使用可選的可變引數定義函式
使用具有可變預設型別的可選引數時出現問題(在使用可選引數定義函式中進行了描述 ),這可能會導致意外行為。 ****
說明
這個問題是因為一個函式的預設引數初始化一旦被該功能時,在點定義,並不能 (像許多其他語言)當函式被稱為。預設值儲存在函式物件的 __defaults__
成員變數中。
def f(a, b=42, c=[]):
pass
print(f.__defaults__)
# Out: (42, [])
對於不可變型別(參見 Argument 傳遞和可變性 ),這不是問題,因為沒有辦法改變變數; 它只能被重新分配,保持原始值不變。因此,後續保證具有相同的預設值。但是,對於可變型別,通過呼叫其各種成員函式,原始值可以變異。因此,不保證對函式的連續呼叫具有初始預設值。
def append(elem, to=[]):
to.append(elem) # This call to append() mutates the default variable "to"
return to
append(1)
# Out: [1]
append(2) # Appends it to the internally stored list
# Out: [1, 2]
append(3, []) # Using a new created list gives the expected result
# Out: [3]
# Calling it again without argument will append to the internally stored list again
append(4)
# Out: [1, 2, 4]
注意: 某些 IDE(如 PyCharm)會在將可變型別指定為預設屬性時發出警告。
解
如果要確保預設引數始終是你在函式定義中指定的引數,那麼解決方案是始終使用不可變型別作為預設引數。
當需要使用可變型別作為預設值時,實現此目的的常用習慣是使用 None
(不可變)作為預設引數,然後如果它等於 None
則將實際預設值分配給引數變數。
def append(elem, to=None):
if to is None:
to = []
to.append(elem)
return to