Lorsque j'essaie de ou/et deux ensembles en utilisant &=
et |=
opérateur, j'ai obtenu un résultat bizarre.
s1 = {1,2,3}
s2 = {2,3,4}
tmp = s1
tmp &= s2
Comme prévu, tmp sera {2,3}, mais je ne sais pas pourquoi s1
a également changé sa valeur en {2,3}.
Cependant, si je le fais:
tmp = tmp & s2
Ensuite, s1
sera inchangé! Quelqu'un peut-il m'expliquer ce qui se passe en dessous &=
opérateur?
&=
(set.__iadd__
) pour set
est implémenté différemment avec &
(set.__add
) .
set &= ...
est implémenté à l'aide de set.intersection_update
qui met à jour l'ensemble sur place.
Code CPython pertinent (Object/setobject.c
):
set_iand(PySetObject *so, PyObject *other)
{
PyObject *result;
if (!PyAnySet_Check(other))
Py_RETURN_NOTIMPLEMENTED;
result = set_intersection_update(so, other); // <----
if (result == NULL)
return NULL;
Py_DECREF(result);
Py_INCREF(so);
return (PyObject *)so;
}
C'est appelé intersection_update
. retourne l'ensemble s ne gardant que les éléments également trouvés dans t. Comme vous le voyez sur cette image;
Vous reconstruisez d'abord le jeu avec l'intersection.
Copiez l'ensemble par valeur au lieu de par référence
tmp = set(s1)
(Comme s1
est une instance de set
)
Ce n'est pas l'opérateur &=
Qui cause le résultat inattendu, c'est comment Python fonctionne avec le stockage des objets en mémoire, et les référencant avec des variables (noms).
Tout dans Python est un objet, et il est stocké quelque part en mémoire. La déclaration d'une variable indique simplement Python que vous faites référence à un objet spécifique qui est stocké dans un emplacement spécifique dans la mémoire, en utilisant le nom de variable comme référence à cet objet.
Vous pouvez obtenir des informations sur l'emplacement mémoire de l'objet à l'aide de la fonction id()
intégrée, par exemple:
s1 = {1,2,3}
s2 = {2,3,4}
tmp = s1
id(tmp)
1763330653544
id(s1)
1763330653544
Quelques informations sur la fonction id()
intégrée:
Renvoie "l'identité" d'un objet. Il s'agit d'un entier qui est garanti unique et constant pour cet objet pendant sa durée de vie. Deux objets dont la durée de vie ne se chevauche pas peuvent avoir la même valeur id ().
Détail d'implémentation de CPython: il s'agit de l'adresse de l'objet en mémoire.
Lien vers Python dans la fonction id ()
Comme vous pouvez le voir, en utilisant la fonction id()
, l'objet référencé par les noms tmp
et s1
Est le même, car la valeur entière retournée est la même.
Ainsi, lorsque vous modifiez l'un ou l'autre, l'autre change comme wel. En fait, ce que je dis dans la dernière phrase n'est pas techniquement correct, car il n'y a pas de "non plus", juste un objet défini en mémoire avec deux références différentes (tmp
et s1
).
s1 = {3, 4, 5}
s2 = s1
s2.add(6)
s1
{3, 4, 5, 6}
id(s1)
1763330653320
id(s2)
1763330653320
Cependant, ce n'est pas toujours aussi simple, donc si vous voulez comprendre cela, je vous recommande de rechercher Python et référencement des variables).
Real Python semble faire un bon travail pour expliquer le référencement d'objet (avec des noms/variables), lien vers la page .