为父母班级设立的儿童安置计划

时间:2015-06-12 08:51:07

标签: python parent-child parent setattr

我有一个父母和十几个孩子的图书馆:

# 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()

所以,我的问题是:

  1. 这是好事吗?
  2. 如何以更好的方式完成这项工作?

2 个答案:

答案 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的行为。然后,此方法的行为将取决于您如何实例化对象,而不是全局状态。