如何在Snap.py中复制Graph对象?
我尝试使用 copy.deepcopy(graph) 但遇到了一个错误:
我的代码:
new_graph = TNEANet.New()
....
# some define for new_graph
....
copy_graph = copy.deepcopy(new_graph)
执行错误:
TypeError: object.__new__(SwigPyObject) is not safe, use SwigPyObject.__new__()
我还发现这个API有一个定义,API文档。所以我尝试使用 TNEANet(Graph)
来完成这个任务:
new_graph = TNEANet.New()
....
# some define for new_graph
....
copy_graph = TNEANet(new_graph)
执行错误:
TypeError: in method 'new_TNEANet', argument 1 of type 'TSIn &'
2 个回答
1
简短回答
最好的办法是自己复制节点、边和属性。我发现把数据导出到文件再重新加载也能很好地工作,不过如果你在使用PNEANet
,那么属性就不会被复制。这里有一个我用来复制图的方便函数(比逐个遍历要快):
def copy_graph(graph):
tmpfile = '.copy.bin'
# Saving to tmp file
FOut = snap.TFOut(tmpfile)
graph.Save(FOut)
FOut.Flush()
# Loading to new graph
FIn = snap.TFIn(tmpfile)
graphtype = type(graph)
new_graph = graphtype.New()
new_graph = new_graph.Load(FIn)
return new_graph
详细回答
有一种方法可以深度复制你的图:
import snap
new_graph = snap.TNEANet.New()
....
# some define for new_graph
....
copy_graph = snap.TNEANet(new_graph())
(这适用于任何类型的图)
问题在于它返回的是snap.TNEANet
,而我们需要的是snap.PNEANet
。后者在C++实现中只是前者的一个指针,但我们在Python中无法创建这个指针。因此,copy_graph
的功能会比new_graph
少。
解释:
SNAP在Python中使用了一种代理表示,这在某种程度上使得深度复制过程变得复杂。复制构造函数期望的是非代理类型,而你给它的是Python的代理类型。
这会引发一个TypeError
,显示它所知道的第一个构造函数的签名(这个和我们的问题完全无关)。
为了解决这个问题,我们需要给构造函数提供底层的C++类型,这可以通过使用self.__call__()
方法来获得。
但由于C++的(不太好?)实现,snap.TNEANet(new_graph())
输出的是snap.TNEANet
。这意味着这个函数的输出将是一个非代理类型。因此,它将无法与大多数SNAP功能正常工作……
3
你可以使用 ConvertGraph 方法来复制一个图(图在这里指的是一种数据结构)。只需要确保你用的图的类型和你想要的目标类型是一样的就可以了:
graph = snap.TNEANet.New()
graph.AddNode(1)
graph.AddNode(2)
graph.AddEdge(1,2)
copy_graph = snap.ConvertGraph(type(graph), graph)