Rappel sur les types mutables
On a vu que certains types étaient modifiables (mutables) et d’autres non. Les types mutables que nous avons étudiés sont les listes et les dictionnaires.
Cela signifie qu’une fois ces objets instanciés, il est possible d’en modifier la valeur. Ce qui n’est pas la même chose que réassigner une variable car cela affecte toutes les références vers l’objet.
>>> a = b = {}
>>> a[0] = True
>>> a
{0: True}
>>> b
{0: True}
Cela n’est pas possible avec un nombre, une chaîne de caractères ou un tuple, qui ne peuvent pas être modifiés en tant que tels. Et la réassignation d’une variable la fait pointer vers une nouvelle valeur, sans affecter les autres références à l’ancienne valeur.
>>> a = b = 3
>>> a = 5
>>> a
5
>>> b
3
Ainsi, toute référence vers un objet mutable va permettre d’en modifier le contenu, ce sera donc le cas aussi pour ces objets passés en arguments à des fonctions. Il faudra alors être très attentif sur ceux-ci.
Paramètres mutables
Ça peut donc être perturbant au premier abord, puisque la modification d’un paramètre altère la valeur passée en argument.
def append_zero(values):
values.append(0)
return values
>>> l = [1, 2, 3]
>>> append_zero(l)
[1, 2, 3, 0]
>>> l
[1, 2, 3, 0]
Ce n’est pas le cas avec une redéfinition qui crée une nouvelle instance (et donc oublie la référence précédente).
def append_zero(values):
values = values + [0]
return values
>>> l = [1, 2, 3]
>>> append_zero(l)
[1, 2, 3, 0]
>>> l
[1, 2, 3]
Attention cependant à l’opérateur +=
des listes qui opère une modification sur la liste existante plutôt qu’une réaffectation sur une nouvelle liste.
def append_zero(values):
values += [0]
return values
>>> l = [1, 2, 3]
>>> append_zero(l)
[1, 2, 3, 0]
>>> l
[1, 2, 3, 0]
Effets de bord
Modifier ainsi les valeurs passées en paramètres provoque ce que l’on appelle des effets de bord, c’est-à-dire que l’exécution de la fonction affecte un état extérieur, elle n’est pas reproductible dans les mêmes conditions.
On dit aussi qu’elle n’est pas « pure » (contrairement à une fonction purement mathématique qui ne ferait que calculer un nouveau résultat à partir des paramètres).
Parfois, ces effets de bord sont désirables, mais ils ne le sont pas toujours. Dans les cas où on veut les éviter, on privilégiera alors des types immutables (tuples par exemple) ou l’on créera des copies des objets reçus en paramètres.
def append_zero(values):
values = list(values) # on crée une copie
values.append(0)
return values