Python Language Mutable vs immuable


Exemple

Il existe deux types de types dans Python. Types immuables et types mutables.

Immuables

Un objet d'un type immuable ne peut pas être modifié. Toute tentative de modification de l'objet entraînera la création d'une copie.

Cette catégorie comprend: les entiers, les flottants, les complexes, les chaînes, les octets, les tuples, les plages et les frozensets.

Pour mettre en évidence cette propriété, jouons avec l' id builtin. Cette fonction renvoie l'identificateur unique de l'objet passé en paramètre. Si l'identifiant est le même, c'est le même objet. Si cela change, alors c'est un autre objet. (Certains disent que c'est en fait l'adresse mémoire de l'objet, mais méfiez-vous d'eux, ils sont du côté obscur de la force ...)

>>> a = 1
>>> id(a)
140128142243264
>>> a += 2
>>> a
3
>>> id(a)
140128142243328

Ok, 1 n'est pas 3 ... Dernières nouvelles ... Peut-être pas. Cependant, ce comportement est souvent oublié en ce qui concerne les types plus complexes, en particulier les chaînes de caractères.

>>> stack = "Overflow"
>>> stack
'Overflow'
>>> id(stack)
140128123955504
>>> stack += " rocks!"
>>> stack
'Overflow rocks!'

Aha! Voir? Nous pouvons le modifier!

>>> id(stack)
140128123911472

Bien qu'il semble que nous puissions changer la chaîne nommée par la stack variables, ce que nous faisons réellement, c'est de créer un nouvel objet pour contenir le résultat de la concaténation. Nous sommes dupes parce que dans le processus, le vieil objet ne va nulle part, donc il est détruit. Dans une autre situation, cela aurait été plus évident:

>>> stack = "Stack"
>>> stackoverflow = stack + "Overflow"
>>> id(stack)
140128069348184
>>> id(stackoverflow)
140128123911480

Dans ce cas, il est clair que si nous voulons conserver la première chaîne, nous avons besoin d’une copie. Mais est-ce si évident pour d'autres types?

Exercice

Maintenant, sachant comment fonctionnent les types immuables, que diriez-vous avec le morceau de code ci-dessous? Est-ce sage?

s = ""
for i in range(1, 1000):
    s += str(i)
    s += ","

Mutables

Un objet de type mutable peut être modifié et modifié in situ . Aucune copie implicite n'est faite.

Cette catégorie comprend: les listes, les dictionnaires, les séries et les ensembles.

Continuons à jouer avec notre petite fonction d' id .

>>> b = bytearray(b'Stack')
>>> b
bytearray(b'Stack')
>>> b = bytearray(b'Stack')
>>> id(b)
140128030688288
>>> b += b'Overflow'
>>> b
bytearray(b'StackOverflow')
>>> id(b)
140128030688288

(En remarque, j'utilise des octets contenant des données ascii pour clarifier mon propos, mais souvenez-vous que les octets ne sont pas conçus pour contenir des données textuelles. La force peut me pardonner.)

Qu'avons-nous? Nous créons un bytearray, le modifions et en utilisant l' id , nous pouvons nous assurer qu'il s'agit du même objet, modifié. Pas une copie

Bien sûr, si un objet doit être modifié souvent, un type mutable fait un travail bien meilleur qu'un type immuable. Malheureusement, la réalité de cette propriété est souvent oubliée lorsqu'elle fait le plus mal.

>>> c = b
>>> c += b' rocks!'
>>> c
bytearray(b'StackOverflow rocks!')

D'accord...

>>> b
bytearray(b'StackOverflow rocks!')

Waiiit une seconde ...

>>> id(c) == id(b)
True

Effectivement. c n'est pas une copie de b . c est b .

Exercice

Maintenant, vous comprenez mieux quel effet secondaire un type mutable implique, pouvez-vous expliquer ce qui ne va pas dans cet exemple?

>>> ll = [ [] ]*4 # Create a list of 4 lists to contain our results
>>> ll
[[], [], [], []]
>>> ll[0].append(23) # Add result 23 to first list
>>> ll
[[23], [23], [23], [23]]
>>> # Oops...