0

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

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方法来实现这一点?

4

1 回答 1

1

这被称为“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 的鸭子类型使得这种“面向 mixin 的编程”特别简单:在 的实现中Func3Mixin.func3,你可以使用 的属性和方法SuperClass,尽管它Func3Mixin本身并没有以SuperClass任何方式静态相关,因为你知道任何作为 a 的运行时对象Func3Mixin也将是SuperClass.


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


此外,值得指出的是,您的任何类实际上都不能像编写的那样使用——任何调用任何方法的尝试都会引发 a TypeError,因为它们缺少self参数。但是你用猴子补丁的方式func3,它会以完全相同的方式失败func1。(我上面勾勒的替代方案也是如此。)


最后,这里所有的类都是经典类而不是新式的,因为你忘记了SuperClass继承自object。如果你不能改变SuperClass,当然,这不是你的错——但你可能想通过让你的子类(或Intermediate)乘以继承object来修复它SuperClass。(如果您一直在关注:是的,这意味着您可以混入新式类。尽管在幕后您必须了解元类才能理解原因。)

于 2013-04-24T01:37:05.310 回答