モジュールに触れることなく、モジュール内のクラスをカスタムメイドのサブクラスに「魔法のように」置き換える方法は次のとおりです。これは通常のサブクラス化手順からほんの数行余分にあるため、ボーナスとしてサブクラス化の(ほぼ)すべてのパワーと柔軟性を提供します。たとえば、これにより、必要に応じて新しい属性を追加できます。
import networkx as nx
class 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 works
graph = nx.generators.random_graphs.fast_gnp_random_graph(7, 0.6)
graph.plot()
ほとんどの場合、これがあなたが知る必要があるすべてですが、1つの落とし穴があります。メソッドのオーバーライドは、そのサブクラスではなく、に__new__
のみ影響します。nx.Graph
たとえばnx.gn_graph
、のインスタンスを返す、を呼び出すと、nx.DiGraph
派手な拡張機能はありません。使用するサブクラスのそれぞれをサブクラス化nx.Graph
し、必要なメソッドと属性を追加する必要があります。ミックスインを使用すると、 DRYの原則に従いながら、サブクラスを一貫して拡張することが容易になる場合があります。
この例は簡単に思えるかもしれませんが、モジュールにフックするこの方法は、発生する可能性のあるすべての小さな問題をカバーする方法で一般化するのは困難です。手元の問題に合わせて調整する方が簡単だと思います。たとえば、フックしているクラスが独自のカスタム__new__
メソッドを定義している場合、それを置き換える前にそれを格納し、の代わりにこのメソッドを呼び出す必要がありますobject.__new__
。