2

と という 2 つのクラスがあるとしますManagerGraphここで、各 Graph はそのマネージャーへの参照を持ち、各 Manager はそれが所有するグラフのコレクションへの参照を持ちます。2つのことができるようになりたい

1) グラフをコピーします。これは、新しいグラフが古いグラフと同じマネージャーを参照することを除いて、ディープコピーを実行します。

2) マネージャーをコピーします。これにより、新しいマネージャーが作成され、それが所有するすべてのグラフもコピーされます。

これを行う最善の方法は何ですか?独自のディープコピー実装を展開する必要はありcopy.deepcopyませんが、標準ではこのレベルの柔軟性が提供されていないようです。

4

3 に答える 3

3

特別なメソッドにmemodict渡されるものを確認することで、これを簡単に行うことができます。__deepcopy__

class Graph(object):
    def __init__(self, manager=None):
        self.manager = None if manager is None else weakref.ref(manager)
    def __deepcopy__(self, memodict):
        manager = self.manager()
        return Graph(memodict.get(id(manager), manager))

class Manager(object):
    def __init__(self, graphs=[]):
        self.graphs = graphs
        for g in self.graphs:
            g.manager = weakref.ref(self)

ここでは、とweakref.refの間のサイクルを断ち切るために使用していると仮定しています。他のものを使用している場合は、必要に応じて調整してください。GraphManager

>>> m = Manager([Graph(), Graph()])
>>> mc = copy.deepcopy(m)
>>> [g.manager() is mc for g in mc.graphs]
[True, True]
>>> copy.deepcopy(m.graphs[0]).manager() is m
True
于 2012-08-17T22:48:14.977 に答える
1

グラフで参照されている他のオブジェクトがない場合 (単純なフィールドのみ)、copy.copy(graph)コピーを作成するcopy.deepcopy(manager)必要がありますが、 のようなリストがあると仮定して、マネージャーとそのグラフをコピーする必要がありますmanager.graphs

しかし、一般的にはあなたの言うとおりです。copyモジュールにはこのような柔軟性がありません。少し手の込んだ状況では、おそらく独自のものを作成する必要があります。

于 2012-08-17T22:40:04.587 に答える
0

クラスのコピー プロトコルを定義するような単純なものはどうでしょうか。

import copy

class Graph(object):

    def __init__(self):
        self.data = [1,2,3]
        self.manager = None

    def __getstate__(self):
        return {
            'data': self.data,
            'manager': self.manager
        }

    def __setstate__(self, state):
        self.manager = state.pop('manager')
        for name, val in state.iteritems():
            setattr(self, name, copy.copy(val))


class Manager(object):

    def __init__(self):
        self.data = [4,5,6]
        self.graphs = []

    def __getstate__(self):
        return {
            'data': self.data,
            'graphs': self.graphs
        }

    def __setstate__(self, state):
        self.graphs = [copy.copy(g) for g in state.pop('graphs')]
        for name, val in state.iteritems():
            setattr(self, name, copy.copy(val))

マネージャーを参照として定義し、他のすべてを必要な方法でコピーするだけです。

例:

In [2]: m1 = Manager()

In [3]: g1 = Graph()

In [4]: g1.manager = m1

In [5]: g2 = copy.copy(g1)

In [6]: g2.manager is g1.manager
Out[6]: True

In [7]: g2.data is g1.data
Out[7]: False

In [8]: m1.graphs.extend([g1,g2])

In [9]: m2 = copy.copy(m1)

In [10]: m2.data is m1.data
Out[10]: False

In [11]: m2.graphs[0] is m1.graphs[0]
Out[11]: False

In [12]: m2.graphs[0].manager is m1.graphs[0].manager
Out[12]: True
于 2012-08-17T23:05:48.457 に答える