我有一个一对多的类继承结构如下:
class SuperClass:
def func1():
print 'hello'
def func2():
print 'ow'
class SubClass1(SuperClass):
def func1():
print 'hi'
class SubClass2(SuperClass):
def func1():
print 'howdy'
...
我想为类A添加功能,以便在创建类B和C(等等)时可以使用它,但我不能直接编辑类A的代码。我目前的解决方案是:
def func3():
print 'yes!'
SuperClass.func3 = func3
是否有更好和/或更python的方法来实现这一点?
这被称为"monkeypatching",在某些情况下是完全合理的。
例如,如果您必须使用依赖于SuperClass
的其他人的代码(您无法修改),并且您需要更改该代码的行为,那么您唯一真正的选择是替换SuperClass
上的方法。
然而,在你的情况下,似乎没有任何好的理由这样做。你定义了SuperClass
的所有子类,那么为什么不在中间添加另一个类呢?
class Intermediate(SuperClass):
def func3():
pass
class SubClass1(Intermediate):
def func1():
print 'hi'
这对于"应该在SuperClass
中但没有的功能"来说不够好,如果其他代码你无法控制需要该功能……但是当只有你的代码需要该功能时,它就一样好,而且更简单。
如果连子类都不在您的控制之下,通常您可以从为的每个类派生一个新类。例如:
class Func3Mixin(object):
def func3():
pass
class F3SubClass1(SubClass1, Func3Mixin):
pass
class F3SubClass2(SubClass2, Func3Mixin):
pass
现在你只是构造F3SubClass1
的实例而不是SubClass1
。期望使用SubClass1
实例的代码可以使用F3SubClass1
实例。Python的鸭子类型使得这种"面向混合的编程"特别简单:在Func3Mixin.func3
的实现内部,您可以使用SuperClass
的属性和方法,尽管Func3Mixin
本身在静态上与SuperClass
没有任何关系,因为您知道任何是Func3Mixin
的运行时对象也将是SuperClass
。
同时,即使monkeypatching 是合适的,它也不一定是最好的答案。例如,如果你要修补一些第三方代码中的错误,这些代码有一个很好的许可证和源代码存储库,这使得维护你自己的补丁很容易,你可以只分叉它,创建一个固定的副本,并使用它来代替原来的。
另外,值得指出的是,您的所有类实际上都不能像编写的那样使用-任何尝试调用任何方法都会引发TypeError
,因为它们缺少self
参数。但是你在func3
中使用monkeypatched的方式,它将以与func1
完全相同的方式失败。(对于我在上面概述的替代方案也是如此。)
最后,这里所有的类都是经典类,而不是新式类,因为您忘记让SuperClass
继承object
。当然,如果不能更改SuperClass
,那不是您的错,但您可能希望通过使子类(或Intermediate
)继承object
和SuperClass
来修复它。(如果你一直注意的话:是的,这意味着你可以加入新式风格。尽管在幕后,您必须理解元类才能理解其中的原因。