Mutabilité détermine s'il est possible de modifier un objet sans changer son identifiant (adresse en mémoire) :
Impact sur les fonctions :
Exemple :
def f(lst): lst.append(42) data = [] f(data) print(data) # [42] def f2(x): x += 1 n = 1 f2(n) print(n) # 1
"Que renverra le code suivant ?"
def foo(bar=[]): bar.append(1) return bar print(foo()) print(foo())
Réponse : Renvoie :
[1]
[1, 1]
Parce que les arguments de fonction sont initialisés une seule fois lors de la définition, et non à chaque appel. Les listes (et autres objets mutables) dans les arguments de fonction — piège populaire.
Histoire
Dans une API REST, une liste était renvoyée par une fonction avec un paramètre par défaut :
def get_default_items(items=[]): items.append('x') return items
Après plusieurs appels, on a découvert que la liste grossissait, alors qu'on s'attendait à n'obtenir qu'un seul élément.
Histoire
Dans une fonction, on prévoyait de "remplacer" une chaîne :
def replace_word(word): word.replace('a', 'b') word = 'data' replace_word(word) print(word) # On s'attendait à 'dbtb', on obtient 'data'
Les méthodes str ne modifient pas la chaîne d'origine, mais retournent une nouvelle, cependant, la valeur du résultat retourné a été ignorée.
Histoire
En travaillant avec des structures imbriquées :
original = [[1, 2], [3, 4]] copy = original[:] copy[0][0] = -1 print(original) # [[-1, 2], [3, 4]]
Une copie superficielle a été utilisée, pensant que seule la copie avait été modifiée, mais les objets imbriqués sont restés communs.