我有一对多的类继承结构如下:
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方法来实现这一目标?
答案 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}}。 (如果你一直在关注:是的,这意味着你可以混合使用新式的类型。虽然在封面下你必须理解元类才能理解为什么。)