Comment remplacer le copier/propriétédeepcopy opérations pour un objet Python?
Je comprends la différence entre copy
vs deepcopy
dans le module de copie. J'ai utilisé copy.copy
et copy.deepcopy
avant de réussir, mais c'est la première fois que j'ai réellement passé à propos de la surcharge de la __copy__
et __deepcopy__
méthodes. J'ai déjà Googlé autour et regarda à travers la intégré dans les modules Python à regarder pour les instances de la __copy__
et __deepcopy__
fonctions (par exemple,sets.py
, decimal.py
, et fractions.py
), mais je ne suis pas encore sûr à 100%, j'ai bien compris.
Voici mon scénario:
J'ai un objet de configuration. D'abord, je vais instancier un objet de configuration par défaut avec un ensemble de valeurs. Cette configuration sera remis à plusieurs autres objets (pour s'assurer que tous les objets commencent avec la même configuration). Cependant, une fois que l'interaction de l'utilisateur démarre, chaque objet a besoin pour peaufiner ses configurations de manière indépendante, sans se tourmenter les uns les autres configurations (qui me dit que je vais avoir besoin de faire des deepcopys de ma première configuration à la main autour d').
Voici un exemple d'objet:
class ChartConfig(object):
def __init__(self):
#Drawing properties (Booleans/strings)
self.antialiased = None
self.plot_style = None
self.plot_title = None
self.autoscale = None
#X axis properties (strings/ints)
self.xaxis_title = None
self.xaxis_tick_rotation = None
self.xaxis_tick_align = None
#Y axis properties (strings/ints)
self.yaxis_title = None
self.yaxis_tick_rotation = None
self.yaxis_tick_align = None
#A list of non-primitive objects
self.trace_configs = []
def __copy__(self):
pass
def __deepcopy__(self, memo):
pass
Quelle est la bonne façon de mettre en œuvre la copy
et deepcopy
méthodes sur cet objet afin de garantir copy.copy
et copy.deepcopy
me donner le bon comportement?
- Cela fonctionne? Sont-il des problèmes?
- Je pensais que j'étais toujours eu des problèmes avec des références partagées, mais il est tout à fait possible, j'ai foiré d'ailleurs. Je vais doubler vérifier basé sur @MortenSiebuhr post quand je reçois une chance et de mise à jour avec les résultats.
- De mon actuellement compréhension limitée je m'attends à copier.propriétédeepcopy(ChartConfigInstance) pour renvoyer une nouvelle instance qui n'ont pas de références partagées avec l'original (sans réimplanter propriétédeepcopy vous-même). Est-ce incorrect?
Vous devez vous connecter pour publier un commentaire.
Les recommandations pour la personnalisation sont à la fin de la docs page:
Puisque vous semblent ne pas se soucier de décapage de la personnalisation, de la définition de
__copy__
et__deepcopy__
semble définitivement comme la bonne façon de procéder pour vous.Plus précisément,
__copy__
(la copie) est assez facile dans votre cas...:__deepcopy__
serait similaire (acceptant unmemo
arg trop), mais avant le retour, il aurait pu faire appelself.foo = deepcopy(self.foo, memo)
pour n'importe quel attributself.foo
que les besoins profonds de la copie (essentiellement les attributs qui sont des conteneurs -- les listes, les dicts, non des objets primitifs qui détiennent d'autres choses par leur__dict__
s).__getstate__
/__setstate__
pour mettre en œuvre la copie. Ou suis-je trompé?__copy__
/__deepcopy__
.self.foo = deepcopy(self.foo, memo)
... ? N'avez-vous pas vraiment direnewone.foo = ...
?__init__
. Ce n'est pas ce que la copie n'. Il y a aussi très souvent un cas d'utilisation où le décapage et la copie doivent être différentes. En fait, je ne sais même pas pourquoi copier essaie d'utiliser le décapage protocole par défaut. La copie est dans la manipulation de la mémoire, le décapage est pour la croix-époque persistance; ils sont complètement différents des choses qui ont peu de rapport à l'autre.__init__
newone.foo
est beaucoup plus intuitif, cependant.Mettre ensemble Alex Martelli la réponse de Rob Young commentaire vous obtenez le code suivant:
imprime
ici
__deepcopy__
remplit lememo
dict pour éviter les excès de la copie dans le cas où l'objet en lui-même est référencé à partir de son membre.class Transporter has no attribute '__new__'
(python 2.7). Je suis en train de remplacer__deepcopy__
Transporter
?Transporter
?__deepcopy__
devraient inclure un test d'éviter une récursion infinie: <!-- langue: lang-python --> d = id(auto) résultat = memo.get(d, None) si le résultat n'est pas Rien: résultat de retourmemo[id(self)]
est utilisé pour éviter une récursion infinie. J'ai mis en place un petit exemple: ce qui suggère quecopy.deepcopy()
en interne abandonne l'appel à un objet si sonid()
est une clé dememo
, correct? Il est également intéressant de noter quedeepcopy()
semble le faire sur son propre par défaut, ce qui rend difficile d'imaginer un cas où la définition de__deepcopy__
manuellement est réellement nécessaire...Suivantes Pierre excellente réponse, pour mettre en œuvre une coutume propriétédeepcopy, avec un minimum de modification de la valeur par défaut de mise en œuvre (par exemple la modification d'un champ comme j'en avais besoin) :
Je suis peut-être un peu sur les détails, mais voilà;
De la
copier
docs;En d'autres termes:
copy()
sera seulement la copie de l'élément supérieur et de laisser le reste comme les pointeurs dans la structure d'origine.deepcopy()
sera copie de façon récursive sur tout.Qui est,
deepcopy()
est ce que vous avez besoin.Si vous avez besoin de faire quelque chose de vraiment spécifique, vous pouvez remplacer
__copy__()
ou__deepcopy__()
, comme décrit dans le manuel. Personnellement, je serais probablement de mettre en œuvre une plaine de la fonction (par exempleconfig.copy_config()
ou tel) pour le faire il est clair qu'elle n'est pas standard Python comportement.__copy__(
) et__deepcopy__()
. docs.python.org/library/copy.htmlIl n'est pas clair à partir de votre problème, pourquoi vous avez besoin de redéfinir ces méthodes, puisque vous ne voulez pas le faire tout de personnalisation pour les méthodes de copie.
De toute façon, si vous ne souhaitez personnaliser la copie en profondeur (par exemple, par le partage de certains attributs et de copier les autres), voici une solution:
__deepcopy__
méthode de réinitialisation puisqu'il aura__deepcopy__
= None?__deepcopy__
méthode n'est pas trouvé (ouobj.__deepcopy__
renvoie None),deepcopy
retombe sur le standard deep-fonction de copie. Ceci peut être vu ici__deepcopy__=None
attribut à partir du clone. Voir le nouveau code.La
copy
module utilise introduite éventuellement le__getstate__()
/__setstate__()
décapage protocole, de sorte que ces sont aussi des cibles valides pour remplacer.L'implémentation par défaut retourne et fixe le
__dict__
de la classe, de sorte que vous n'avez pas à appelersuper()
et de se soucier de Eino Gourdin de l'astuce, ci-dessus.Bâtiment sur Antony Hatchkins " propre réponse, voici ma version où la classe en question découle d'une autre classe personnalisée (s).t. nous devons appeler les
super
):