web-dev-qa-db-ja.com

Pythonでコンストラクタをコピーしますか?

python?にコピーコンストラクターがありますか?そうでない場合、同様の何かを達成するために何をしますか?

状況は、ライブラリを使用していて、そこにあるクラスの1つを追加機能で拡張し、ライブラリから取得したオブジェクトを自分のクラスのインスタンスに変換できるようにすることです。

77
Zitrax

コピーモジュール が必要だと思います

import copy

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

pickle と同じようにコピーを制御できます。

61
Tom Dunham

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
22
qwerty9967

コピーコンストラクターの私の通常の実装の簡単な例:

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)
14
Godsmith

あなたの状況については、引数としてライブラリのクラスのインスタンスを取り、すべての適用可能な属性がコピーされたクラスのインスタンスを返すクラスメソッド(または静的メソッドまたは別の関数)を記述することをお勧めします。

11
David Z

@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行列データをコピーできない限り再計算する必要のある他の属性やメソッドを大量に追加します。ソリューションを検索すると、この質問が見つかりました。

4
hobs

新しいクラスは属性をコピーするだけでよいという点で、似たような状況があります。したがって、@ 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
2
upandacross