為什麼不能用可變物件作為預設引數的值
阿新 • • 發佈:2020-12-09
為什麼不能用可變物件作為預設引數的值
看一個例子
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中新增一個元素
-
第三次、四次依此類推
那麼我們應該如何避免前面那種情況發生呢?
就是不要用可變物件作為引數的`預設值`。