1. 程式人生 > 實用技巧 >為什麼不能用可變物件作為預設引數的值

為什麼不能用可變物件作為預設引數的值

為什麼不能用可變物件作為預設引數的值

看一個例子

def abc(a, b):
    b.append(a)
    print(b)
    return b

if __name__ == '__main__':
    abc(1, [])
    abc(2, [])
    abc(3, [])
結果和預期的一樣:
[1]
[2]
[3]
如果傳入引數是預設引數呢?
def abc(a, b=[]):
    b.append(a)
    print(b)
    return b

if __name__ == '__main__':
    abc(1)
    abc(2)
    abc(3)
結果如下:
[1]
[1, 2]
[1, 2, 3]

震驚!

BUG解釋

  • def是一條可執行語句,Python 直譯器執行 def 語句時,就會在記憶體中就建立了一個函式物件(此時,函式裡面的程式碼邏輯並不會執行,因為還沒呼叫嘛),在全域性名稱空間,有一個函式名(變數叫 func)會指向該函式物件,記住,至始至終,不管該函式呼叫多少次,函式物件只有一個,就是function object,不會因為呼叫多次而出現多個函式物件。

  • 函式物件生成之後,它的屬性:名字和預設引數列表都將初始化完成。

      # 函式的名字
      >>> abc.__name__  
      'abc'
    
      # 函式的預設引數列表
      >>> abc.__defaults__  
      ([1, 2, 3],)
    
  • 初始化完成時,屬性 default 中的第一個預設引數 b 指向一個空列表.

  • 當函式第一次被呼叫時,就是第一次執行 abc()時,開始執行函式裡面的邏輯程式碼(此時函式不再需要初始化了),程式碼邏輯就是往b中新增一個值為1的元素

  • 第二次呼叫 func(),繼續往numbers中新增一個元素

  • 第三次、四次依此類推

那麼我們應該如何避免前面那種情況發生呢?

就是不要用可變物件作為引數的`預設值`。