扩展超类的所有子类

时间:2013-04-24 01:30:31

标签: python inheritance dry

我有一对多的类继承结构如下:

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

是否有更好的和/或更多的pythonic方法来实现这一目标?

1 个答案:

答案 0 :(得分:1)

这被称为“monkeypatching”,在某些情况下是完全合理的。

例如,如果您必须使用依赖于SuperClass的其他人的代码(您无法修改),并且您需要更改该代码的行为,那么您唯一真正的选择是替换{{上的方法1}}。


但是,在您的情况下,似乎没有任何充分理由这样做。您正在定义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就好了。 Python的鸭子打字使得这种“面向混合的编程”变得特别简单:在F3SubClass1的实现中,你可以使用Func3Mixin.func3的属性和方法,尽管事实SuperClass本身与Func3Mixin在任何方面都不是静态相关的,因为您知道任何SuperClass的运行时对象也将是Func3Mixin


同时,即使monkeypatching 合适,也不一定是最好的答案。例如,如果您正在修补某些第三方代码中的错误,那么该代码具有良好的许可证和源代码存储库,可以轻松维护您自己的补丁,您只需分叉它,创建一个固定的副本,并使用它而不是原始。


此外,值得指出的是,您的类中没有任何类实际可用,因为任何尝试调用任何方法都会引发SuperClass,因为它们缺少TypeError参数。但是你在self中进行monkeypatched的方式,它将以与func3完全相同的方式失败。 (我在上面概述的替代方案也是如此。)


最后,这里的所有课程都是经典课程而不是新课程,因为您忘记了func1继承自SuperClass。如果您无法更改object,当然,这不是您的错 - 但您可能希望通过使您的子类(或SuperClass)从Intermediate和{object多次继承来修复它{1}}。 (如果你一直在关注:是的,这意味着你可以混合使用新式的类型。虽然在封面下你必须理解元类才能理解为什么。)