Вот как «волшебным образом» заменить класс в модуле на пользовательский подкласс, не касаясь модуля. Это всего лишь несколько дополнительных строк из обычной процедуры создания подклассов, и, следовательно, дает вам (почти) всю мощь и гибкость подклассов в качестве бонуса. Например, это позволяет вам добавлять новые атрибуты, если вы хотите.
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) is called
2. If the returned object is a subclass of nx.Graph,
__init__ is called on the object
3. The object is returned as the instance
Мы заменим 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()
В большинстве случаев это все, что вам нужно знать, но есть одна ошибка. Наше переопределение метода __new__
влияет только на nx.Graph
, но не на его подклассы. Например, если вы вызываете nx.gn_graph
, который возвращает экземпляр nx.DiGraph
, у него не будет ни одного из наших необычных расширений. Вам необходимо создать подкласс каждого из подклассов nx.Graph
, с которым вы хотите работать, и добавить необходимые методы и атрибуты. Использование смешанных модулей может упростить последовательное расширение подклассов при соблюдении принципа DRY .
Хотя этот пример может показаться достаточно простым, этот метод подключения к модулю сложно обобщить так, чтобы охватить все небольшие проблемы, которые могут возникнуть. Я полагаю, что легче приспособить это к проблеме под рукой. Например, если класс, к которому вы подключаетесь, определяет свой собственный метод __new__
, вам необходимо сохранить его перед заменой и вызвать этот метод вместо object.__new__
.