Ответ 1
Я думаю, вам нужен модуль копирования
import copy
x = copy.copy(y) # make a shallow copy of y
x = copy.deepcopy(y) # make a deep copy of y
вы можете управлять копированием во многом так же, как вы управляете pickle.
Есть ли конструктор копирования в python? Если бы не то, что я сделал бы для достижения чего-то подобного?
Ситуация в том, что я использую библиотеку, и я расширил один из классов там с дополнительными функциями, и я хочу, чтобы иметь возможность конвертировать объекты, которые я получаю из библиотеки, в экземпляры моего собственного класса.
Я думаю, вам нужен модуль копирования
import copy
x = copy.copy(y) # make a shallow copy of y
x = copy.deepcopy(y) # make a deep copy of y
вы можете управлять копированием во многом так же, как вы управляете pickle.
В python конструктор копирования может быть определен с использованием аргументов по умолчанию. Допустим, вы хотите, чтобы нормальный конструктор запускал функцию non_copy_constructor(self)
, и конструктор копирования должен запускать copy_constructor(self, orig)
. Затем вы можете сделать следующее:
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
В вашей ситуации я бы предложил написать метод класса (или это может быть статический метод или отдельная функция), который принимает в качестве аргумента экземпляр класса библиотеки и возвращает экземпляр вашего класса со всеми применимыми атрибутами, скопированными более.
Простой пример моей обычной реализации конструктора копирования:
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)
Основываясь на @Godsmith мыслей и обращаясь к @Zitrax, нужно (я думаю) сделать копию данных для всех атрибутов внутри конструктора:
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))
Этот класс ConfusionMatrix
наследует pandas.DataFrame
и добавляет массу других атрибутов и методов, которые необходимо перерасчитать, если только other
матричные данные могут быть скопированы. Поиск решения - вот как я нашел этот вопрос.
У меня есть аналогичная ситуация, отличающаяся тем, что новому классу нужно только копировать атрибуты. Таким образом, используя идею @Dunham и добавляя некоторую специфику к предложению @meisterluk, метод @meisterluk "copy_constructor" может быть:
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
Выход:
foo1
two: <type 'int'>, 2
one: <type 'int'>, 1
foo2
two: <type 'int'>, 2
one: <type 'str'>, one