扩展超类的所有子类



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

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)继承objectSuperClass来修复它。(如果你一直注意的话:是的,这意味着你可以加入新式风格。尽管在幕后,您必须理解元类才能理解其中的原因。

最新更新