Python 函式和物件的預設參數 示範(常見陷阱說明)

這裡有一個自訂的 say_hello function (函式),可以傳入人名:
    
def say_hello(name):
    print(f'Hello {name}!')
    

執行範例:
    
say_hello('Ruyut')  # Hello Ruyut!
    

假設要在沒有傳入參數的情況下自動使用預設值可以怎麼做?
    
def say_hello(name='World'):
    print(f'Hello {name}!')
    

執行範例:
    
say_hello('Ruyut')  # Hello Ruyut!
say_hello()  # Hello World!
    

陣列陷阱

假設有一個自訂的 function (函式),會傳入一個陣列,經過「為了方便說明而被省略的複雜的計算」後會在陣列中加入資料(這裡只是簡單的加入 1 做示範)並回傳:
    
def my_function(data):
    # 省略複雜的計算
    # 反正結果就是 陣列 加入內容
    data.append(1)
    return data
    

測試一下:
    
result = my_function([5, 4, 3])
print(result)  # [5, 4, 3, 1]
    

從上面的例子我們學到了設定預設值得方式:
    
def my_function(data=[]):
    # 省略複雜的計算
    # 反正結果就是 陣列 加入內容
    data.append(1)
    return data
    

測試一下:
    
print(my_function())  # [1]
print(my_function())  # [1, 1]
print(my_function())  # [1, 1, 1]
    

咦?為什麼多次執行後就錯了?
    
print(my_function())  # [1]
print(my_function())  # [1, 1]
print(my_function())  # [1, 1, 1]
    

透過查看官方文件可以發現「當函式呼叫時預設值由左到右在計算時會被定義並執行」所以在一開始就已經被定義,不管使用幾次都會是同一個「預先定義」好的記憶體位置,而官方也有給出正確的做法:
    
def my_function(data=None):
    if data is None:
        data = []
    # 省略複雜的計算
    # 反正結果就是 陣列 加入內容
    data.append(1)
    return data
    

執行結果:
    
print(my_function())  # [1]
print(my_function())  # [1]
    

物件的預設參數

現在有一個 User 物件:
    
class User:
    def __init__(self, name, interest):
        self.name = name
        self.interest = interest
    

    
user1 = User('John', ['music', 'movie'])
    

現在我們已經知道在 預設參數 放入 [] 會出現共用記憶體位置的問題:
    
class User:
    def __init__(self, name, interest=[]):
        self.name = name
        self.interest = interest
        
        
user1 = User('A')
user2 = User('B')
user1.interest.append('book')  # ['book', 'music']
user2.interest.append('music')  # ['book', 'music']

print(user1.interest)
print(user2.interest)
    

使用 三元運算子 我們可以這樣解決:
    
class User:
    def __init__(self, name, interest=None):
        self.name = name
        self.interest = [] if interest is None else interest
    



參考資料:
python.docs - 8.7. Function definitions

留言