web-dev-qa-db-fra.com

Python: & = opérateur

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?

20
OhMyGosh

&= (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;
}
12
falsetru

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;

enter image description here

Vous reconstruisez d'abord le jeu avec l'intersection.

6
GLHF

Copiez l'ensemble par valeur au lieu de par référence

tmp = set(s1)

(Comme s1 est une instance de set)

3
SomethingSomething

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 .

0
Rik Schoonbeek