投基类派生的类蟒(或扩展类的更Python的方式)
-
27-09-2019 - |
题
我需要延长Networkx Python包,并添加了一些方法的Graph
类为我特别需要
我想过做这simplying派生新类发言权NewGraph
,并添加所需的方法方式。
但是存在其中创建networkx和返回Graph
对象几个其他功能(例如生成随机图形)。我现在需要把这些Graph
物体进入NewGraph
对象,这样我可以用我的新方法。
什么是这样做的最佳方式?或者我应该在一个完全不同的方式来解决这一问题?
解决方案
如果你是刚刚加入的行为,而不是依赖于另外一个实例值,可以分配给对象的__class__
:
from math import pi
class Circle(object):
def __init__(self, radius):
self.radius = radius
def area(self):
return pi * self.radius**2
class CirclePlus(Circle):
def diameter(self):
return self.radius*2
def circumference(self):
return self.radius*2*pi
c = Circle(10)
print c.radius
print c.area()
print repr(c)
c.__class__ = CirclePlus
print c.diameter()
print c.circumference()
print repr(c)
打印:
10
314.159265359
<__main__.Circle object at 0x00A0E270>
20
62.8318530718
<__main__.CirclePlus object at 0x00A0E270>
这是接近了“投”,你可以在Python中获得,并且像在C铸造,但也不是没有给内容的某些思想工作要做。我已相当有限的例子,但如果你能留在限制范围内(只需添加行为,没有新的实例瓦尔),那么这可能会帮助您解决问题。
其他提示
下面是如何“神奇”与定制的子类的模块中替换一类不接触模块。这只是从一个正常的程序子类一些额外的线路,因此给你(几乎)所有功能和子类作为奖金的灵活性。例如,这允许你添加新的属性,如果你想。
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__
的。
如果一个功能是创建图形对象,则不能把它们变成NewGraph对象。
另一选择是NewGraph是有一个图形而不是一个图形。您委派图形的方法你有图形对象,你可以用任何Graph对象到一个新的NewGraph对象:
class NewGraph:
def __init__(self, graph):
self.graph = graph
def some_graph_method(self, *args, **kwargs):
return self.graph.some_graph_method(*args, **kwargs)
#.. do this for the other Graph methods you need
def my_newgraph_method(self):
....
有关您的简单的情况下,你也可以写你的子类__init__
这样并分配从图中数据结构的指针,你的子类的数据。
from networkx import Graph
class MyGraph(Graph):
def __init__(self, graph=None, **attr):
if graph is not None:
self.graph = graph.graph # graph attributes
self.node = graph.node # node attributes
self.adj = graph.adj # adjacency dict
else:
self.graph = {} # empty graph attr dict
self.node = {} # empty node attr dict
self.adj = {} # empty adjacency dict
self.edge = self.adj # alias
self.graph.update(attr) # update any command line attributes
if __name__=='__main__':
import networkx as nx
R=nx.gnp_random_graph(10,0.4)
G=MyGraph(R)
您也可以在作业使用复制()或deepcopy的(),但如果你正在做的,你还不如用
G=MyGraph()
G.add_nodes_from(R)
G.add_edges_from(R.edges())
要加载图形数据。
您可以简单地创建NewGraph
对象派生的新Graph
并有__init__
功能包括像self.__dict__.update(vars(incoming_graph))
作为第一行,您可以定义自己的属性了。通过这种方式,你基本上是从你到一个新的对象Graph
,从Graph
派生复制所有的属性,但您特制的酱汁。
class NewGraph(Graph):
def __init__(self, incoming_graph):
self.__dict__.update(vars(incoming_graph))
# rest of my __init__ code, including properties and such
用法:
graph = function_that_returns_graph()
new_graph = NewGraph(graph)
cool_result = function_that_takes_new_graph(new_graph)
你们试过 [Python的]铸造基类派生的类
我已经测试过它,而且似乎它的工作原理。此外我认为这种方法是位因为低于一个不执行除了以下一个更好的初始化强>导出的功能的功能。
c.__class__ = CirclePlus