zen*_*nna 38 python inheritance base-class derived-class
我需要扩展Networkx python包并Graph为我的特殊需要添加一些方法
我想这样做的方法是简单地推导出一个新类说NewGraph,并添加所需的方法.
然而,networkx中还有一些其他函数可以创建和返回Graph对象(例如,生成随机图).我现在需要将这些Graph对象转换为NewGraph对象,以便我可以使用我的新方法.
这样做的最佳方式是什么?或者我应该以完全不同的方式解决问题?
Pau*_*McG 52
如果您只是添加行为,而不依赖于其他实例值,则可以分配给对象__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)
Run Code Online (Sandbox Code Playgroud)
打印:
10
314.159265359
<__main__.Circle object at 0x00A0E270>
20
62.8318530718
<__main__.CirclePlus object at 0x00A0E270>
Run Code Online (Sandbox Code Playgroud)
这与你在Python中可以得到的"强制转换"一样接近,就像在C中进行投射一样,如果不考虑这个问题就不可能完成.我发布了一个相当有限的示例,但如果您可以保持在约束内(只添加行为,没有新的实例变量),那么这可能有助于解决您的问题.
Lau*_*low 12
以下是如何"神奇地"使用定制的子类替换模块中的类而不触及模块.它只是普通子类化过程中的一些额外行,因此为您提供(几乎)子类化的所有功能和灵活性作为奖励.例如,如果您愿意,这允许您添加新属性.
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()
Run Code Online (Sandbox Code Playgroud)
到目前为止,这与正常的子类化完全相同.现在我们需要将这个子类挂钩到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()
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,这只是你需要知道的,但有一个问题.我们覆盖的__new__方法只会影响nx.Graph它的子类.例如,如果你调用nx.gn_graph,返回一个实例nx.DiGraph,它将没有我们花哨的扩展.您需要子类化nx.Graph您希望使用的每个子类,并添加所需的方法和属性.使用混合可以更容易在遵循DRY原则的同时一致地扩展子类.
虽然这个例子看起来很简单,但这种挂钩模块的方法难以概括,涵盖了可能出现的所有小问题.我相信只是根据手头的问题量身定做更容易.例如,如果您要连接的类定义了自己的自定义__new__方法,则需要在替换它之前存储它,并调用此方法而不是object.__new__.
| 归档时间: |
|
| 查看次数: |
27925 次 |
| 最近记录: |