Existe-t-il un constructeur de copie dans python? Sinon, que ferais-je pour obtenir quelque chose de similaire?
La situation est que j'utilise une bibliothèque et que j'y ai étendu une des classes avec des fonctionnalités supplémentaires et que je veux pouvoir convertir les objets que je reçois de la bibliothèque en instances de ma propre classe.
Je pense que vous voulez le module de copie
import copy
x = copy.copy(y) # make a shallow copy of y
x = copy.deepcopy(y) # make a deep copy of y
vous pouvez contrôler la copie de la même manière que vous contrôlez pickle .
Dans python le constructeur de copie peut être défini en utilisant des arguments par défaut. Disons que vous voulez que le constructeur normal exécute la fonction non_copy_constructor(self)
et que le constructeur de copie exécute copy_constructor(self, orig)
. Ensuite, vous pouvez effectuer les opérations suivantes:
class Foo:
def __init__(self, orig=None):
if orig is None:
self.non_copy_constructor()
else:
self.copy_constructor(orig)
def non_copy_constructor(self):
# do the non-copy constructor stuff
def copy_constructor(self, orig):
# do the copy constructor
a=Foo() # this will call the non-copy constructor
b=Foo(a) # this will call the copy constructor
Un exemple simple de mon implémentation habituelle d'un constructeur de copie:
import copy
class Foo:
def __init__(self, data):
self._data = data
@classmethod
def from_foo(cls, class_instance):
data = copy.deepcopy(class_instance._data) # if deepcopy is necessary
return cls(data)
Pour votre situation, je suggérerais d'écrire une méthode de classe (ou ce pourrait être une méthode statique ou une fonction distincte) qui prend comme argument une instance de la classe de la bibliothèque et retourne une instance de votre classe avec tous les attributs applicables copiés.
En s'appuyant sur @ Godsmith train de pensée et en répondant au besoin de @ Zitrax (je pense) de faire la copie de données pour tous les attributs du constructeur:
class ConfusionMatrix(pd.DataFrame):
def __init__(self, df, *args, **kwargs):
try:
# Check if `df` looks like a `ConfusionMatrix`
# Could check `isinstance(df, ConfusionMatrix)`
# But might miss some "ConfusionMatrix-elligible" `DataFrame`s
assert((df.columns == df.index).all())
assert(df.values.dtype == int)
self.construct_copy(df, *args, **kwargs)
return
except (AssertionError, AttributeError, ValueError):
pass
# df is just data, so continue with normal constructor here ...
def construct_copy(self, other, *args, **kwargs):
# construct a parent DataFrame instance
parent_type = super(ConfusionMatrix, self)
parent_type.__init__(other)
for k, v in other.__dict__.iteritems():
if hasattr(parent_type, k) and hasattr(self, k) and getattr(parent_type, k) == getattr(self, k):
continue
setattr(self, k, deepcopy(v))
Cette classe ConfusionMatrix
hérite d'un pandas.DataFrame
et ajoute une tonne d'autres attributs et méthodes qui doivent être recalculés à moins que les données de la matrice other
puissent être copiées. C'est à la recherche d'une solution que j'ai trouvé cette question.
J'ai une situation similaire qui diffère en ce que la nouvelle classe n'a besoin que de copier les attributs. Ainsi, en utilisant l'idée de @ Dunham et en ajoutant une certaine spécificité à la suggestion de @ meisterluk, la méthode "copy_constructor" de @ meisterluk pourrait être:
from copy import deepcopy
class Foo(object):
def __init__(self, myOne=1, other=None):
self.two = 2
if other <> None:
assert isinstance(other, Foo), "can only copy instances of Foo"
self.__dict__ = deepcopy(other.__dict__)
self.one = myOne
def __repr__(self):
out = ''
for k,v in self.__dict__.items():
out += '{:>4s}: {}, {}\n'.format(k,v.__class__,v)
return out
def bar(self):
pass
foo1 = Foo()
foo2 = Foo('one', foo1)
print '\nfoo1\n',foo1
print '\nfoo2\n',foo2
Le résultat:
foo1
two: <type 'int'>, 2
one: <type 'int'>, 1
foo2
two: <type 'int'>, 2
one: <type 'str'>, one