Mutowalność definiuje, czy obiekt może być zmieniony bez zmiany jego identyfikatora (adresu w pamięci):
Wpływ na funkcje:
Przykład:
def f(lst): lst.append(42) data = [] f(data) print(data) # [42] def f2(x): x += 1 n = 1 f2(n) print(n) # 1
"Co wypisze poniższy kod?"
def foo(bar=[]): bar.append(1) return bar print(foo()) print(foo())
Odpowiedź: Wypisze:
[1]
[1, 1]
Ponieważ argumenty funkcji są inicjalizowane tylko raz przy definiowaniu, a nie przy każdym wywołaniu. Listy (i inne obiekty mutowalne) w argumentach funkcji — to popularna pułapka.
Historia
W REST API zwracano listę przez funkcję z domyślnym parametrem:
def get_default_items(items=[]): items.append('x') return items
Po kilku wywołaniach zauważono, że lista rośnie, chociaż oczekiwano otrzymania tylko jednego elementu.
Historia
W funkcji planowano "zastąpić" słowo:
def replace_word(word): word.replace('a', 'b') word = 'data' replace_word(word) print(word) # Oczekiwano 'dbtb', otrzymano 'data'
Metody str nie zmieniają oryginalnego łańcucha, ale zwracają nowy, jednak wartość zwracanego wyniku została zignorowana.
Historia
Pracując z zagnieżdżonymi strukturami:
original = [[1, 2], [3, 4]] copy = original[:] copy[0][0] = -1 print(original) # [[-1, 2], [3, 4]]
Użyto płytkiego kopiowania, sądząc, że zmienili tylko kopię, ale zagnieżdżone obiekty pozostały wspólne.