Copier le constructeur en python?
Existe-t-il un constructeur de copie en python ? Si ce n'est pas le cas, que ferais-je pour réaliser quelque chose de similaire ?
La situation est que j'utilise une bibliothèque et j'ai étendu l'une des classes avec des fonctionnalités supplémentaires et je veux pouvoir convertir les objets que je reçois de la bibliothèque en instances de ma propre classe.
6 réponses
Je pense que vous voulez l' 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.
En 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 faire ce qui suit:
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
Pour votre situation, je suggère d'écrire une méthode de classe (ou il pourrait s'agir d'une méthode statique ou d'une fonction distincte) qui prend comme argument une instance de la classe de la bibliothèque et renvoie une instance de votre classe avec tous les attributs applicables copiés.
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)
Construire sur le train de pensée de @Godsmith {[6] } et répondre 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))
Ce ConfusionMatrix
la classe 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
ne puissent être copiées. La recherche d'une solution est la façon dont j'ai trouvé cette question.
J'ai une situation similaire différant en ce que la nouvelle classe n'a besoin que de copier des 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
La sortie:
foo1
two: <type 'int'>, 2
one: <type 'int'>, 1
foo2
two: <type 'int'>, 2
one: <type 'str'>, one