618 votes

Copie profonde d'un dict en python

Je voudrais faire une copie profonde d'une dict en python. Malheureusement, le .deepcopy() n'existe pas pour la méthode dict . Comment je fais ça ?

>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = my_dict.deepcopy()
Traceback (most recent calll last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'deepcopy'
>>> my_copy = my_dict.copy()
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
7

La dernière ligne devrait être 3 .

Je voudrais que les modifications dans my_dict n'ont pas d'impact sur l'instantané my_copy .

Comment je fais ça ? La solution doit être compatible avec Python 3.x.

3 votes

Je ne sais pas si c'est un doublon, mais ceci : stackoverflow.com/questions/838642/python-dictionnaire-deepcopy est terriblement proche.

862voto

Lasse V. Karlsen Points 148037

Pourquoi pas :

import copy
d = { ... }
d2 = copy.deepcopy(d)

Python 2 ou 3 :

Python 3.2 (r32:88445, Feb 20 2011, 21:30:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import copy
>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = copy.deepcopy(my_dict)
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
3
>>>

22 votes

En effet, cela fonctionne pour l'exemple trop simplifié que j'ai donné. Mes clés ne sont pas des nombres mais des objets. Si je lis la documentation du module de copie, je dois déclarer une méthode __copy__()/__deepcopy__() pour les clés. Merci beaucoup de m'y avoir conduit !

5 votes

Y a-t-il une différence entre les codes Python 3.2 et 2.7 ? Ils me semblent identiques. Si oui, il vaudrait mieux un seul bloc de code et une déclaration "Works for both Python 3 and 2".

75 votes

Il convient également de mentionner copy.deepcopy n'est pas sûr. J'ai appris cela de la manière la plus dure. D'autre part, en fonction de votre cas d'utilisation, json.loads(json.dumps(d)) est sans fil, et fonctionne bien.

73voto

theBuzzyCoder Points 1086

dict.copy() est une fonction de copie superficielle pour le dictionnaire
id est une fonction intégrée qui vous donne l'adresse de la variable

Vous devez d'abord comprendre "pourquoi ce problème particulier se produit-il ?".

In [1]: my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}

In [2]: my_copy = my_dict.copy()

In [3]: id(my_dict)
Out[3]: 140190444167808

In [4]: id(my_copy)
Out[4]: 140190444170328

In [5]: id(my_copy['a'])
Out[5]: 140190444024104

In [6]: id(my_dict['a'])
Out[6]: 140190444024104

L'adresse de la liste présente dans les deux dicts pour la clé 'a' pointe vers le même emplacement.
Par conséquent, lorsque vous changez la valeur de la liste dans mon_dict, la liste dans ma_copie change également.


Solution pour la structure de données mentionnée dans la question :

In [7]: my_copy = {key: value[:] for key, value in my_dict.items()}

In [8]: id(my_copy['a'])
Out[8]: 140190444024176

Ou vous pouvez utiliser deepcopy comme mentionné ci-dessus.

69voto

xpro-fedtest Points 468

Python 3.x

de copy import deepcopy

my_dict = {'one': 1, 'two': 2}
new_dict_deepcopy = deepcopy(my_dict)

Sans deepcopy, je suis incapable de supprimer le dictionnaire des noms d'hôtes de mon dictionnaire de domaine.

Sans deepcopy, j'obtiens l'erreur suivante :

"RuntimeError: dictionary changed size during iteration"

...lorsque j'essaie de supprimer l'élément souhaité de mon dictionnaire à l'intérieur d'un autre dictionnaire.

import socket
import xml.etree.ElementTree as ET
from copy import deepcopy

domain est un objet de type dictionnaire

def remove_hostname(domain, hostname):
    domain_copy = deepcopy(domain)
    for domains, hosts in domain_copy.items():
        for host, port in hosts.items():
           if host == hostname:
                del domain[domains][host]
    return domain

Exemple de sortie : [original]domaines = {'localdomain' : {'localhost' : {'all' : '4000'}}}

[nouveau]domaines = {'localdomain' : {} }}

Donc ce qui se passe ici, c'est que j'itère sur une copie d'un dictionnaire plutôt que d'itérer sur le dictionnaire lui-même. Avec cette méthode, vous êtes en mesure de supprimer des éléments si nécessaire.

-1voto

antoinet Points 32

Dans les deux cas, dans Python 2 et 3, qu'en est-il du trop simple et efficace :

> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
> my_new_dict = dict(my_dict)

Maintenant, faisons en sorte que mon_nouveau_dict soit une copie de mon_dict :

> my_dict
{'a': [1, 2, 3], 'b': [4, 5, 6]}
> my_new_dict
{'a': [1, 2, 3], 'b': [4, 5, 6]}

Maintenant, est-ce que mon_nouveau_dict est une copie profonde de mon_dict ?

> my_new_dict['hey'] = 'how are you doing?'
> my_dict
{'a': [1, 2, 3], 'b': [4, 5, 6]}
> my_new_dict
{'a': [1, 2, 3], 'b': [4, 5, 6], 'hey': 'how are you doing?'}

Oui, il l'est :-)

-2voto

Rafael Monteiro Points 63

J'aime et j'ai beaucoup appris de Lasse V. Karlsen. Je l'ai modifié dans l'exemple suivant, qui met assez bien en évidence la différence entre les copies superficielles de dictionnaires et les copies profondes :

    import copy

    my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
    my_copy = copy.copy(my_dict)
    my_deepcopy = copy.deepcopy(my_dict)

Maintenant, si vous changez

    my_dict['a'][2] = 7

et faire

    print("my_copy a[2]: ",my_copy['a'][2],",whereas my_deepcopy a[2]: ", my_deepcopy['a'][2])

vous obtenez

    >> my_copy a[2]:  7 ,whereas my_deepcopy a[2]:  3

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X