Mutable et immutable
- François Brucker
- Pierre Brucker
Les 5 type d'objets de base (int, float, complex, bool et str) sont non modifiables (python dira non mutables). Ceci signifie que les méthodes et opérations sur ces objets ne peuvent les modifier :
- si
icontient un entier,i = i + 1créera un nouvel entier qui sera associé à la variablei "coucou".replace("c", "b")créera une nouvelle chaîne de caractères
Les listes, ensembles et dictionnaires sont eux modifiables (python dira mutables), c'est à dire que leurs méthodes peuvent les modifier :
l.append("x")modifiera la listeld["un"] = 1modifiera le dictionnaireden lui ajoutant une clée.add("un")modifiera l'ensembleeen lui ajoutant un élément
Il est crucial de comprendre cela car les variables ne sont que des associations à des objets, et plusieurs variables différentes peuvent être associée à un même objet. Vérifions cela avec la fonction id.
Si on crée deux listes, elles seront différentes, donc leur id le sera aussi, même si leur contenu est identique :
>>> x = [1, 2]
>>> y = [1, 2]
>>> id(x)
4381752640
>>> id(y)
4381751744
L'id sera certainement différent chez vous, mais les deux id seront différents.
En revanche, associer une liste à une variable ne change pas la liste :
>>> x = [1, 2]
>>> id(x)
4381803264
>>> y = x
>>> id(y)
4381803264
L'id sera certainement différent chez vous, mais il sera identique. Les variables x et y sont associées à la même liste :
>>> x.append('?')
>>> print(x)
[1, 2, '?']
>>> print(y)
[1, 2, '?']
En conclusion, il faut faire très attention lorsque l'on passe des listes en paramètres de fonction.
Si vous jouez avec la fonction id vous serez certainement surpris de constater que :
>>> x = 1
>>> y = 1
>>> id(x)
4378755312
>>> id(y)
4378755312
Ceci est une optimisation de l'interpréteur python. Comme les entiers sont non modifiables, on peut associer le même entier à plusieurs variables sans soucis.
La remarque précédente montre tout l'intérêt d'utiliser des objets non mutables. Il 'y aura jamais d'effet de bords lors de passage de paramètres. En revanche, à chaque modification, il faudra recréer un objet, ce qui peut être long. C'est un compromis à avoir : la sécurité vs la rapidité. C'est pourquoi par défaut :
- une chaîne de caractère est non modifiables (elles sont souvent crées une fois pour toute dans un programme)
- une liste est modifiable. L'utilisation des listes dans un programme nécessite souvent de la modifier.
Il existe des objets non modifiable pouvant être utilisé à la place des listes et des ensembles :
- un
tuplepour une liste. Elle se crée en remplaçant les[]d'une liste par des():(1, 2, 3)crée un tuple à 3 éléments. Il pourra être utilisé comme une liste mais on ne pourra jamais lui ajouter ou modifier ses éléments. - un
frozensetsera le pendant non mutable d'un ensemble. On place les éléments directement à la création et ils ne peuvent plus être modifiés ensuite.
Il n'existe pas d'équivalent non mutable aux dictionnaires.
On peut alors utiliser des tuples et des frozenset comme éléments d'un ensemble ou comme clé de dictionnaires.
Par exemple l'ensemble de tous les sous-ensemble de ${1, 2}$ s'écrira :
>>> x = {frozenset(), frozenset([1]), frozenset([2]), frozenset([1, 2])}
>>> x
{frozenset(), frozenset({2}), frozenset({1}), frozenset({1, 2})}
Le tuple vide s'écrira (,) (ou tuple()) pour la différentier la notation () qui est la parenthèse vide.