Скопировать конструктор в python?

Есть ли конструктор копирования в python? Если бы не то, что я сделал бы для достижения чего-то подобного?

Ситуация в том, что я использую библиотеку, и я расширил один из классов там с дополнительными функциями, и я хочу, чтобы иметь возможность конвертировать объекты, которые я получаю из библиотеки, в экземпляры моего собственного класса.

Ответ 1

Я думаю, вам нужен модуль копирования

import copy

x = copy.copy(y)        # make a shallow copy of y
x = copy.deepcopy(y)    # make a deep copy of y

вы можете управлять копированием во многом так же, как вы управляете pickle.

Ответ 2

В 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

Ответ 3

В вашей ситуации я бы предложил написать метод класса (или это может быть статический метод или отдельная функция), который принимает в качестве аргумента экземпляр класса библиотеки и возвращает экземпляр вашего класса со всеми применимыми атрибутами, скопированными более.

Ответ 4

Простой пример моей обычной реализации конструктора копирования:

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)

Ответ 5

Основываясь на @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 матричные данные могут быть скопированы. Поиск решения - вот как я нашел этот вопрос.

Ответ 6

У меня есть аналогичная ситуация, отличающаяся тем, что новому классу нужно только копировать атрибуты. Таким образом, используя идею @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