[地雷] 函數裡的預設參數,最好不要使用可變物件(mutable object) - tsungjung411/python-study GitHub Wiki

程式範例

def append_position(a, b, x_list = []):
    for x in range(a, b + 1):
        x_list.append(x)
    # end-of-for
    return x_list
# end-of-def
        
default_x_list = [1, 2]
x_list1 = append_position(3, 5, default_x_list)
print(x_list1) # [1, 2, 3, 4, 5]...預期結果
print(x_list1 == default_x_list) # True

x_list2 = append_position(1, 3)
print(x_list2) #[1, 2, 3]...預期結果

x_list3 = append_position(1, 5)
print(x_list3) # [1, 2, 3, 1, 2, 3, 4, 5]...非預期結果
print(x_list3 == x_list2) # True

執行結果:

[1, 2, 3, 4, 5]
True
[1, 2, 3]
[1, 2, 3, 1, 2, 3, 4, 5]
True

結果說明:

  • 預設參數 x_list = []執行參數初始化後,就不再執行第二次,因此後續的操作都是拿到同一個物件
  • 只要預設參數是「可變物件(mutable object)」,都會有此情形,使用上要特別小心
  • 同理,類別的成員也盡量不要使用「可變物件」,遇到的問題如同上面。每個產生出來物件,都拿到同樣類別的成員物件

正確寫法:

def append_position(a, b, x_list = None):
    if x_list == None:
        x_list = []
    # end-of-if
    
    for x in range(a, b + 1):
        x_list.append(x)
    # end-of-for
    return x_list
# end-of-def

其他參考

關鍵字:

  • 地雷, 陷阱, 臭蟲(bug),
  • 方法(method), 函數(function), 宣告
  • 默認參數/預設參數(default parameter), 無引數(no argument)
  • 可變物件/可變動物件(mutable object), 不可變物件/不可變動物件(immutable object)