Comment copier un dictionnaire et seulement éditer la copie

quelqu'un peut-il me l'expliquer? Ca n'a aucun sens pour moi.

je copie un dictionnaire dans un autre et édite le second et les deux sont changés. Pourquoi est-ce arrivé?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
496
demandé sur poke 2010-03-18 00:07:06

17 réponses

Python never copie implicitement des objets. Lorsque vous définissez dict2 = dict1 , vous les faites se référer au même objet dict exact, donc quand vous le mutez, toutes les références à lui continuent de se référer à l'objet dans son état actuel.

si vous voulez copier le dict (ce qui est rare), vous devez le faire explicitement avec

dict2 = dict(dict1)

ou

dict2 = dict1.copy()
570
répondu Mike Graham 2010-03-17 21:09:08

quand vous assignez dict2 = dict1 , vous ne faites pas une copie de dict1 , il en résulte que dict2 est juste un autre nom pour dict1 .

pour copier les types mutables comme les dictionnaires, utilisez copy / deepcopy du module copy .

import copy

dict2 = copy.deepcopy(dict1)
363
répondu Imran 2010-03-17 21:13:48
>>> x={'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> u=x.copy()
>>> v=dict(x)
>>> import copy
>>> w=copy.deepcopy(x)
>>> x['a']=10
>>> x
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> u
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> v
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> w
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> x['b']['m']=40
>>> x
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> u
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> v
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> w
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
114
répondu gpanda 2017-05-01 14:20:15

sur python 3.5+ il y a un moyen plus facile d'obtenir une copie superficielle en utilisant l'opérateur ** unpackaging. Défini par Pep 448 .

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

* * déballage du dictionnaire dans un nouveau dictionnaire qui est ensuite assigné à dict2.

nous pouvons également confirmer que chaque dictionnaire a une identification distincte.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

si une copie profonde est nécessaire alors copie.propriétédeepcopy() est encore du chemin à parcourir.

42
répondu PabTorre 2018-01-29 14:09:24

vous pouvez également juste faire un nouveau dictionnaire avec une compréhension de dictionnaire. Cela évite l'importation de copie.

dout = dict((k,v) for k,v in mydict.items())

bien sûr en python > = 2.7 vous pouvez faire:

dout = {k:v for k,v in mydict.items()}

Mais pour l'arrière compat. le top méthode est la meilleure.

32
répondu Dashing Adam Hughes 2014-12-02 21:42:28

les instructions D'affectation en Python ne copient pas les objets, elles créent des liaisons entre une cible et un objet.

ainsi, dict2 = dict1 , il en résulte une autre liaison entre dict2 et l'objet auquel dict1 se réfère.

si vous voulez copier un dict, vous pouvez utiliser le copy module . Le module de copie a deux interfaces:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

la différence entre copie superficielle et copie profonde n'est pertinente que pour objets composés (objets qui contiennent d'autres objets, comme des listes ou des instances de classe):

Un copie construit un nouvel objet composé, puis (dans la mesure du possible) insère des références pour les objets trouvés dans l'original.

Un copie construit un nouvel objet composé et puis, de manière récursive, insère des copies en elle de la les objets trouvés dans l'original.

par exemple, en python 2.7.9:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

et le résultat est:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]
13
répondu loosen 2016-12-10 12:25:25

la meilleure et la plus facile des façons de créer une copie d'un dict dans les deux Python 2.7 et 3 sont...

pour créer une copie du dictionnaire simple(à un seul niveau):

1. utilisant la méthode dict () , au lieu de générer une référence qui pointe vers le dict existant.

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. intégré update() méthode de python dictionnaire.

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

pour créer une copie du dictionnaire emboîté ou complexe:

utilise le module intégré copie , qui fournit une opération générique de copie peu profonde et profonde. Ce module est présent en Python 2.7 et 3.*

import copy

my_dict2 = copy.deepcopy(my_dict1)
10
répondu Emrit 2018-07-16 14:10:49

vous pouvez copier et éditer la copie nouvellement construite en une seule fois en appelant le constructeur dict avec des arguments de mots clés supplémentaires:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
9
répondu Frerich Raabe 2016-10-25 12:41:03

toute variable en python (des trucs comme dict1 ou str ou __builtins__ est un pointeur vers un "objet" platonique caché à l'intérieur de la machine.

si vous mettez dict1 = dict2 , vous pointez juste dict1 vers le même objet (ou emplacement de mémoire, ou n'importe quelle analogie que vous aimez) comme dict2 . Maintenant, l'objet référencé par dict1 est le même objet référencé par dict2 .

vous pouvez vérifier: dict1 is dict2 devrait être True . En outre, id(dict1) devrait être le même que id(dict2) .

Vous voulez dict1 = copy(dict2) , ou dict1 = deepcopy(dict2) .

la différence entre copy et deepcopy ? deepcopy s'assurera que les éléments de dict2 (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).

7
répondu wisty 2010-03-17 23:57:26

dict2 = dict1 ne copie pas le dictionnaire. Il vous donne simplement le programmeur une seconde façon ( dict2 ) de se référer au même dictionnaire.

6
répondu 2010-03-17 21:09:44

cela m'a embrouillé aussi, d'abord, parce que je venais d'un arrière-plan en C.

En C, une variable est un emplacement dans la mémoire avec un type défini. Attribuer à une variable copie les données dans l'emplacement de la mémoire de la variable.

mais en Python, les variables agissent plus comme des pointeurs vers des objets. Ainsi, attribuer une variable à une autre ne fait pas de copie, Cela fait simplement pointer le nom de la variable sur le même objet.

6
répondu Craig McQueen 2010-03-18 00:39:58

dict1 est un symbole qui renvoie à un objet sous-jacent du dictionnaire. L'affectation de dict1 à dict2 ne fait qu'attribuer la même référence. Changer la valeur d'une clé via le symbole dict2 change l'objet sous-jacent, ce qui affecte aussi dict1 . Ceci est source de confusion.

il est beaucoup plus facile de raisonner sur des valeurs immuables que des références, donc faites des copies chaque fois que possible:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

c'est syntaxiquement le identique à:

one_year_later = dict(person, age=26)
5
répondu Petrus Theron 2016-12-23 17:04:02

parce que python fonctionne avec référence, donc quand vous avez fait dict2 = dict1 vous passez une référence à dict2, qui était la même que dict1. Donc, quand vous faites un changement dans dict1 ou dict2 vous changez une référence, et les deux dicts chantent. Désolé si je me trompe quelque chose sur l'anglais.

1
répondu Rodrigo Moraes 2016-12-22 23:14:09

Comme d'autres l'ont expliqué, le dict ne pas faire ce que vous voulez. Mais en Python2 (et probablement 3 Aussi) vous pouvez facilement créer une classe ValueDict qui copie avec = de sorte que vous pouvez être sûr que l'original ne changera pas.

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

veuillez vous référer au modèle de modification de lvalue discuté ici: Python 2.7 - syntaxe clean pour la modification de lvalue . La principale observation est que str et int 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, s'il vous plaît également noter que rien n'est magiquement spécial au sujet de str ou int . dict peut être utilisé de la même manière, et je peux penser à de nombreux cas où ValueDict a un sens.

1
répondu personal_cloud 2017-09-16 23:48:15

parce que, dict2 = dict1, dict2 tient la référence à dict1. Dict1 et dict2 pointent tous deux vers le même endroit dans la mémoire. C'est juste un cas normal en travaillant avec des objets mutables en python. Lorsque vous travaillez avec des objets mutables en python, vous devez être prudent, car il est difficile à déboguer. Comme dans l'exemple suivant.

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

Cet exemple, l'intention est d'obtenir tous les id d'utilisateur, y compris bloqué id. Que nous avons obtenu d'ids variable mais nous avons aussi mis à jour la valeur de my_users involontairement. lors de l'extension de la id avec blocked_ids my_users s'est mis à jour parce que id consultez my_users .

0
répondu Vkreddy Komatireddy 2017-07-31 13:26:07
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

il y a plusieurs façons de copier un objet Dict, j'utilise simplement

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)
0
répondu George Cao 2018-09-30 14:59:25

vous pouvez utiliser directement:

dict2 = eval(repr(dict1))

où objet dict2 est une copie indépendante de dict1, donc vous pouvez modifier dict2 sans affecter dict1.

cela fonctionne pour tout type d'objet.

-5
répondu Viiik 2017-08-02 10:21:08