我有一个父母和十几个孩子的图书馆:
# mylib1.py:
#
class Foo(object):
def __init__(self, a):
self.a = a
class FooChild(Foo):
def __init__(self, a, b):
super(FooChild, self).__init__(a)
self.b = b
# more children here...
现在我想用一个简单的(但有点特殊的,用于另一种方法)方法扩展该库。所以我想改变父类,并使用它的孩子。
# mylib2.py:
#
import mylib1
def fooMethod(self):
print 'a={}, b={}'.format(self.a, self.b)
setattr(mylib1.Foo, 'fooMethod', fooMethod)
现在我可以像这样使用它:
# way ONE:
import mylib2
fc = mylib2.mylib1.FooChild(3, 4)
fc.fooMethod()
或者像这样:
# way TWO:
# order doesn't matter here:
import mylib1
import mylib2
fc = mylib1.FooChild(3, 4)
fc.fooMethod()
所以,我的问题是:
答案 0 :(得分:4)
常用方法是使用mixin
如果需要,可以动态添加How do I dynamically add mixins as base classes without getting MRO errors?。
答案 1 :(得分:0)
编程中有一般规则,你应该避免依赖全局状态。换句话说,这意味着你的全局变量应尽可能不变。类(大多数)是全局的。
您的方法称为猴子修补。如果你没有一个非常好的理由来解释它,你应该避免它。这是因为猴子修补违反了上述规则。
想象一下,您有两个独立的模块,它们都使用这种方法。其中一个将Foo.fooMethod设置为某种方法。另一个 - 另一个。然后你以某种方式切换这些模块之间的控制。结果是,很难确定在哪里使用fooMethod。这意味着难以调试问题。
有人(例如Brandon Craig-Rhodes)认为即使在测试中修补也很糟糕。
我建议使用在实例化Foo()类(及其子类)的实例时设置的某个属性,这将控制fooMethod的行为。然后,此方法的行为将取决于您如何实例化对象,而不是全局状态。