假设我有两个类,比如Manager
和Graph
,其中每个图都有一个对它的管理器的引用,每个管理器都有对它拥有的一组图的引用。我希望能够做两件事
1) 复制图形,该图形执行深度复制,但新图形引用的管理器与旧图形相同。
2) 复制经理,这将创建一个新经理并复制它拥有的所有图表。
最好的方法是什么?我不想推出自己的 deepcopy 实现,但标准copy.deepcopy
似乎没有提供这种级别的灵活性。
您可以通过查看传递给__deepcopy__
特殊方法的memodict
来轻松执行此操作:
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
来打破Graph
和Manager
之间的循环;如果你使用其他东西,那么适当地调整。
>>> 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
如果图中没有引用其他对象(只是简单的字段),那么copy.copy(graph)
应该复制一个副本,而copy.deepcopy(manager)
应该复制管理器及其图形,假设有一个列表,例如 manager.graphs
.
但总的来说你是对的,copy
模块没有这种灵活性,对于稍微花哨的情况,你可能需要自己动手。
像为类定义复制协议这样非常简单的事情呢?
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