Je voudrais créer une copie d'un objet. Je veux que le nouvel objet possède toutes les propriétés de l'ancien objet (valeurs des champs). Mais je veux avoir des objets indépendants. Donc, si je change les valeurs des champs du nouvel objet, l'ancien objet ne devrait pas être affecté par cela.
200
Vous voulez dire un objet mutable alors.
En Python 3, les listes obtiennent une
copy
méthode (en 2, vous utiliseriez une tranche pour faire une copie):Copies peu profondes
Les copies superficielles ne sont que des copies du conteneur le plus à l'extérieur.
list.copy
est une copie superficielle:Vous n'avez pas de copie des objets intérieurs. Ils sont le même objet - donc lorsqu'ils sont mutés, le changement apparaît dans les deux conteneurs.
Copies complètes
Les copies profondes sont des copies récursives de chaque objet intérieur.
Les modifications ne sont pas reflétées dans l'original, uniquement dans la copie.
Objets immuables
Les objets immuables n'ont généralement pas besoin d'être copiés. En fait, si vous essayez, Python ne vous donnera que l'objet d'origine:
Les tuples n'ont même pas de méthode de copie, alors essayons-le avec une tranche:
Mais nous voyons que c'est le même objet:
De même pour les chaînes:
et pour les frozensets, même s'ils ont une
copy
méthode:Quand copier des objets immuables
Les objets immuables doivent être copiés si vous avez besoin d'un objet intérieur mutable copié.
Comme nous pouvons le voir, lorsque l'objet intérieur de la copie est muté, l'original ne change pas .
Objets personnalisés
Les objets personnalisés stockent généralement des données dans un
__dict__
attribut ou dans__slots__
(une structure de mémoire de type tuple).Pour créer un objet copiable, définissez
__copy__
(pour les copies superficielles) et / ou__deepcopy__
(pour les copies complètes ).Notez que
deepcopy
conserve un dictionnaire de mémorisationid(original)
(ou numéros d'identité) pour les copies. Pour profiter d'un bon comportement avec des structures de données récursives, assurez-vous que vous n'en avez pas déjà fait une copie et, si vous en avez, renvoyez-la.Faisons donc un objet:
Et
copy
fait une copie superficielle:Et
deepcopy
fait maintenant une copie complète:la source
Copie peu profonde avec
copy.copy()
Copie complète avec
copy.deepcopy()
Documentation: https://docs.python.org/3/library/copy.html
Testé sur Python 3.6.5.
la source
Je pense que ce qui suit devrait fonctionner avec de nombreux classeurs bien comportés en Python:
(Bien sûr, je ne parle pas ici de "copies profondes", qui est une histoire différente, et qui n'est peut-être pas un concept très clair - à quelle profondeur est-elle suffisamment profonde?)
Selon mes tests avec Python 3, pour les objets immuables, comme les tuples ou les chaînes, il renvoie le même objet (car il n'est pas nécessaire de faire une copie superficielle d'un objet immuable), mais pour les listes ou les dictionnaires, il crée une copie superficielle indépendante .
Bien sûr, cette méthode ne fonctionne que pour les classes dont les constructeurs se comportent en conséquence. Cas d'utilisation possibles: faire une copie superficielle d'une classe de conteneur Python standard.
la source
__init__
méthode. Donc, j'ai pensé que cette méthode pouvait être assez bonne pour certains objectifs. Dans tous les cas, je serai intéressé par des commentaires informatifs sur cette suggestion.class Foo(object): def __init__(self, arg): super(Foo, self).__init__() self.arg = arg
Basic comme il se présente. Si je le fais, celafoo = Foo(3) bar = copy(foo) print(foo.arg) # 3 print(bar.arg) # <__main__.Foo object at ...>
signifie que votrecopy
fonction est interrompue, même pour les classes les plus élémentaires. Encore une fois, c'est une astuce intéressante (donc pas de DV), mais pas une réponse.copy.copy
méthode pour faire des copies superficielles, mais, peut-être naïvement, il me semble que ce devrait être la responsabilité de la classe de fournir un "constructeur de copie superficielle". Dans ce cas, pourquoi ne pas lui fournir la même interface quedict
et lelist
faire? Donc, si votre classe veut prendre la responsabilité de copier ses objets, pourquoi ne pas y ajouter uneif isinstance(arg, type(self))
clause__init__
?