Quelqu'un pourrait-il me l'expliquer? Cela n'a aucun sens pour moi.
Je copie un dictionnaire dans un autre et édite le second et les deux sont modifiés. Pourquoi cela arrive-t-il?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
python
python-3.x
dictionary
reference
MadSc13ntist
la source
la source
dict1
etdict2
pointer vers le même dict.Réponses:
Python ne copie jamais implicitement des objets. Lorsque vous définissez
dict2 = dict1
, vous les faites se référer au même objet dict exact, donc lorsque vous le mutez, toutes les références à celui-ci continuent de faire référence à l'objet dans son état actuel.Si vous voulez copier le dict (ce qui est rare), vous devez le faire explicitement avec
ou
la source
dir(1)
pour le voir), mais ils sont implicitement copiés.int
,float
et lesbool
instances sont de vrais objets Python, et b) les objets de ces types ne sont pas copiés implicitement lorsque vous les passez, pas à un niveau sémantique Python à coup sûr et même pas en tant que détail d'implémentation dans CPython.copy.deepcopy()
plutôt quedict()
oudict.copy()
. La réponse concise d' Imran est du bon côté de la raison, contrairement à cette réponse.Lorsque vous attribuez
dict2 = dict1
, vous ne faites pas de copie dedict1
, cela se traduit pardict2
être juste un autre nom pourdict1
.Pour copier les types mutables comme les dictionnaires, utilisez
copy
/deepcopy
ducopy
module.la source
Tandis que
dict.copy()
etdict(dict1)
génère une copie, ce ne sont que des copies superficielles . Si vous voulez une profonde copie,copy.deepcopy(dict1)
est nécessaire. Un exemple:Concernant les copies superficielles vs profondes, à partir des documents du module Python
copy
:la source
w=copy.deepcopy(x)
c'est la ligne clé.dict2 = dict1
etdict2 = copy.deepcopy(dict1)
?Sur python 3.5+, il existe un moyen plus simple de réaliser une copie superficielle en utilisant l'opérateur de décompression **. Défini par Pep 448 .
** décompresse le dictionnaire dans un nouveau dictionnaire qui est ensuite affecté à dict2.
Nous pouvons également confirmer que chaque dictionnaire a un identifiant distinct.
Si une copie complète est nécessaire, alors copy.deepcopy () est toujours le chemin à parcourir.
la source
dict2 = {**dict1, 'key3':'value3'}
Les meilleurs et les plus simples moyens de créer une copie d'un dict en Python 2.7 et 3 sont ...
Pour créer une copie d'un dictionnaire simple (à un niveau):
1. Utilisation de la méthode dict () , au lieu de générer une référence qui pointe vers le dict existant.
2. Utilisation de la méthode intégrée update () du dictionnaire python.
Pour créer une copie d'un dictionnaire imbriqué ou complexe:
Utilisez le module de copie intégré, qui fournit des opérations génériques de copie superficielle et profonde. Ce module est présent à la fois dans Python 2.7 et 3. *
la source
dict()
crée une copie superficielle et non une copie profonde. Cela signifie que si vous avez un imbriqué,dict
l'extérieurdict
sera une copie, mais le dict intérieur sera une référence au dict intérieur d'origine.Vous pouvez également créer un nouveau dictionnaire avec une compréhension du dictionnaire. Cela évite d'importer une copie.
Bien sûr, en python> = 2,7, vous pouvez faire:
Mais pour la compatibilité ascendante, la meilleure méthode est meilleure.
la source
d2 = dict.copy(d1)
ne nécessite pas non plus d'importations.d2 = d1.copy()
dict.items
renvoie déjà une paire clé / valeur itérable. Vous pouvez donc simplement utiliserdict(mydict.items())
(vous pouvez également simplement utiliserdict(mydict)
). Il peut être utile d'avoir la compréhension si vous souhaitez filtrer les entrées.En plus des autres solutions fournies, vous pouvez utiliser
**
pour intégrer le dictionnaire dans un dictionnaire vide, par exemple,shallow_copy_of_other_dict = {**other_dict}
.Vous aurez maintenant une copie "superficielle" de
other_dict
.Appliqué à votre exemple:
Pointeur: différence entre les copies peu profondes et profondes
la source
Les instructions d'affectation en Python ne copient pas d'objets, elles créent des liaisons entre une cible et un objet.
donc,
dict2 = dict1
il en résulte une autre liaison entredict2
et l'objet quidict1
réfère.si vous souhaitez copier un dict, vous pouvez utiliser le
copy module
. Le module de copie a deux interfaces:La différence entre la copie superficielle et la copie profonde n'est pertinente que pour les objets composés (objets qui contiennent d'autres objets, comme des listes ou des instances de classe):
Une copie superficielle construit un nouvel objet composé, puis (dans la mesure du possible) y insère des références aux objets trouvés dans l'original.
Une copie profonde construit un nouvel objet composé, puis, récursivement, y insère des copies des objets trouvés dans l'original.
Par exemple, en python 2.7.9:
et le résultat est:
la source
Vous pouvez copier et modifier la copie nouvellement construite en une seule fois en appelant le
dict
constructeur avec des arguments de mots clés supplémentaires:la source
Cela m'a aussi dérouté, au départ, car je venais d'un milieu C.
En C, une variable est un emplacement en mémoire avec un type défini. L'affectation à une variable copie les données dans l'emplacement de mémoire de la variable.
Mais en Python, les variables agissent plus comme des pointeurs vers des objets. Donc, assigner une variable à une autre ne fait pas de copie, cela fait simplement pointer le nom de la variable vers le même objet.
la source
Chaque variable en python (des trucs comme
dict1
oustr
ou__builtins__
est un pointeur vers un "objet" platonique caché à l'intérieur de la machine.Si vous définissez
dict1 = dict2
, vous pointez simplementdict1
vers le même objet (ou emplacement de mémoire, ou toute analogie que vous aimez) quedict2
. Maintenant, l'objet référencé pardict1
est le même objet référencé pardict2
.Vous pouvez vérifier:
dict1 is dict2
devrait l'êtreTrue
. En outre,id(dict1)
devrait être le même queid(dict2)
.Vous voulez
dict1 = copy(dict2)
, oudict1 = deepcopy(dict2)
.La différence entre
copy
etdeepcopy
?deepcopy
s'assurera que les éléments dedict2
(l'avez-vous pointé sur une liste?) sont également des copies.Je n'utilise pas
deepcopy
beaucoup - c'est généralement une mauvaise pratique d'écrire du code qui en a besoin (à mon avis).la source
dict1
est un symbole qui fait référence à un objet dictionnaire sous-jacent. L'affectationdict1
àdict2
affecte simplement la même référence. La modification de la valeur d'une clé via ledict2
symbole modifie l'objet sous-jacent, ce qui affecte égalementdict1
. Ceci est déroutant.Il est beaucoup plus facile de raisonner sur des valeurs immuables que sur des références, faites donc des copies autant que possible:
Ceci est syntaxiquement le même que:
la source
dict2 = dict1
ne copie pas le dictionnaire. Cela vous donne simplement au programmeur une deuxième façon (dict2
) de faire référence au même dictionnaire.la source
Il existe de nombreuses façons de copier un objet Dict, j'utilise simplement
la source
dict_2 = dict_1.copy()
est beaucoup plus efficace et logique.Comme d'autres l'ont expliqué, la fonction intégrée
dict
ne fait pas ce que vous voulez. Mais en Python2 (et probablement 3 aussi), vous pouvez facilement créer uneValueDict
classe qui copie avec=
ainsi vous pouvez être sûr que l'original ne changera pas.Veuillez vous référer au modèle de modification de lvalue discuté ici: Python 2.7 - syntaxe propre pour la modification de lvalue . L'observation clé est que
str
etint
se comportent comme des valeurs en Python (même si ce sont en fait des objets immuables sous le capot). Pendant que vous observez cela, veuillez également noter que rien n'est magiquement spécial à propos destr
ouint
.dict
peut être utilisé de la même manière, et je pense à de nombreux cas oùValueDict
cela a du sens.la source
le code suivant, qui est sur dicts et qui suit la syntaxe json plus de 3 fois plus vite que deepcopy
la source
j'ai rencontré un comportement particulier en essayant de copier en profondeur la propriété du dictionnaire de la classe sans l'attribuer à une variable
new = copy.deepcopy(my_class.a)
ne fonctionne pas, c'est-à-dire que la modificationnew
modifiemy_class.a
mais si vous le faites
old = my_class.a
et quenew = copy.deepcopy(old)
cela fonctionne parfaitement, c'est-à-dire que la modificationnew
n'affecte pasmy_class.a
Je ne sais pas pourquoi cela se produit, mais j'espère que cela vous fera gagner quelques heures! :)
la source
my_class.a
?parce que, dict2 = dict1, dict2 contient la référence à dict1. Dict1 et dict2 pointent tous deux vers le même emplacement dans la mémoire. C'est juste un cas normal lorsque vous travaillez avec des objets mutables en python. Lorsque vous travaillez avec des objets modifiables en python, vous devez être prudent car il est difficile à déboguer. Tels que l'exemple suivant.
Cet exemple d'intention est d'obtenir tous les ID utilisateur, y compris les ID bloqués. Que nous avons obtenu de la variable ids, mais nous avons également mis à jour la valeur de my_users par inadvertance . lorsque vous avez étendu les identifiants avec block_ids, my_users a été mis à jour car les identifiants font référence à my_users .
la source
Copie à l'aide d'une boucle for:
la source
deepcopy
ce qui est expressément conçu à cet effet?Vous pouvez utiliser directement:
où l'objet dict2 est une copie indépendante de dict1, vous pouvez donc modifier dict2 sans affecter dict1.
Cela fonctionne pour tout type d'objet.
la source
__repr__
pour être reconstruite par eval, ni la classe de l'objet dans la portée actuelle à appeler. Même en restant avec des types intégrés, cela échouera si le même objet est stocké sous plusieurs clés, comme celadict2
aurait alors deux objets distincts. Un dictionnaire auto-référentiel, oùdict1
contient lui-même, contiendra à la placeEllipsis
. Il serait préférable d'utiliserdict1.copy()