冉冉说
这是在不触碰模块的情况下,用定制的子类“神奇地”替换模块中的类的方法。这只是普通子类化程序的几行内容,因此(几乎)为您提供了子类化作为奖励的所有功能和灵活性。例如,如果需要,这允许您添加新属性。import networkx as nxclass NewGraph(nx.Graph): def __getattribute__(self, attr): "This is just to show off, not needed" print "getattribute %s" % (attr,) return nx.Graph.__getattribute__(self, attr) def __setattr__(self, attr, value): "More showing off." print " setattr %s = %r" % (attr, value) return nx.Graph.__setattr__(self, attr, value) def plot(self): "A convenience method" import matplotlib.pyplot as plt nx.draw(self) plt.show()到目前为止,这与普通子类化完全一样。现在,我们需要将此子类连接到networkx模块中,以便将nx.Graph结果的所有实例化都NewGraph替换为一个对象。当您使用实例化nx.Graph对象时,通常会发生以下情况nx.Graph()1.调用nx.Graph .__ new __(nx.Graph)2.如果返回的对象是nx.Graph的子类, 在对象上调用__init__3.对象作为实例返回我们将替换nx.Graph.__new__并使其返回NewGraph。在其中,我们调用的__new__方法object代替的__new__方法NewGraph,因为后者只是调用我们要替换的方法的另一种方式,因此将导致无限递归。def __new__(cls): if cls == nx.Graph: return object.__new__(NewGraph) return object.__new__(cls)# We substitute the __new__ method of the nx.Graph class# with our own. nx.Graph.__new__ = staticmethod(__new__)# Test if it worksgraph = nx.generators.random_graphs.fast_gnp_random_graph(7, 0.6)graph.plot()在大多数情况下,这就是您所需要知道的,但是只有一个陷阱。我们对__new__方法的重写仅影响nx.Graph,而不影响其子类。举例来说,如果您呼叫nx.gn_graph,会传回的实例nx.DiGraph,那么它将没有任何花哨的扩展名。您需要子类化nx.Graph您希望使用的每个子类,并添加所需的方法和属性。使用混入可以更容易地遵循DRY原理来一致地扩展子类。尽管此示例似乎足够简单,但是很难以涵盖可能出现的所有小问题的方式来概括这种挂接到模块中的方法。我相信,针对当前问题进行定制会更容易。例如,如果要插入的类定义了自己的自定义__new__方法,则需要在存储它之前将其替换,然后调用此方法而不是object.__new__。