Değişebilirlik bir nesnenin kimliğini (bellek adresini) değiştirmeden değiştirip değiştiremeyeceğini belirler:
Fonksiyonlar üzerine etkisi:
Örnek:
def f(lst): lst.append(42) data = [] f(data) print(data) # [42] def f2(x): x += 1 n = 1 f2(n) print(n) # 1
"Aşağıdaki kod neyi ekrana yazdırır?"
def foo(bar=[]): bar.append(1) return bar print(foo()) print(foo())
Cevap: Şu sonucu verecek:
[1]
[1, 1]
Çünkü fonksiyon argümanları tanımlandığı anda bir kez başlatılır, her çağrıda değil. Fonksiyonun argümanlarındaki listeler (ve diğer değiştirilebilir nesneler) sıkça tuzak oluşturmaktadır.
Hikaye
REST API'de bir fonksiyonla varsayılan parametre üzerinden liste döndürüldü:
def get_default_items(items=[]): items.append('x') return items
Birkaç çağırmadan sonra, listede beklenenden daha fazla eleman olduğunu fark ettik, bunun yerine sadece bir eleman bekleniyordu.
Hikaye
Bir fonksiyonda bir stringi "değiştirmek" istedik:
def replace_word(word): word.replace('a', 'b') word = 'data' replace_word(word) print(word) # 'dbtb' bekliyorduk, 'data' aldık
str yöntemleri orijinal stringi değiştirmez, yeni bir tane döner, ama dönen değeri göz ardı ettik.
Hikaye
İç içe yapılarla çalışırken:
original = [[1, 2], [3, 4]] copy = original[:] copy[0][0] = -1 print(original) # [[-1, 2], [3, 4]]
Yüzeysel kopyalama kullandık, sadece kopyayı değiştirdiğimizi sanıyorduk, ama iç nesneler ortak kaldı.