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


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

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

6 66

6 ответов:

Я думаю, что вы хотите модуль копирования

import copy

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

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

в 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 класс наследует a 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