首页 > 解决方案 > 调用 super().__init__ 时,如何判断超级初始化是否是 python3 中的 object.__init__?

问题描述

给定一个任意的类继承,我如何找出 if super().__init__ == object.__init__

描述 + 示例

我有这个我不允许触摸的代码,它定义了类 A、B、C、CombinedCba、CombinedAc,每个类都有这个奇怪__init__的约束来验证实例属性。当在所有基类中进行 init 调用时,我们会收到错误:

TypeError: object.__init__() takes exactly one argument (the instance to initialize)

所以为了防止这个错误,当它是对象初始化时,我们应该停止调用超级初始化。我能够编辑 super_init 函数。如何检测超级初始化何时为初始化?如果我知道我无法进行下一次超级初始化调用并消除错误。

# code that I can edit
def super_init(self, super_instance, *args, **kwargs):
  # checking super_instance.__init__ == object.__init__ OR super_instance.__init__ is object.__init__ doesn't work
  # pseudo-code
  if super_instance.__init__ is not object.__init__:
    super_instance.__init__(*args, **kwargs)

# auto generated code is from here on down
class A:
  def __init__(self, *args, **kwargs):
    self.a = kwargs['a']
    assert self.a == 'a'
    super_init(self, super(), *args, **kwargs)

class B:
  def __init__(self, *args, **kwargs):
    self.b = kwargs['b']
    self.some_num = kwargs['some_num']
    assert self.some_num <= 30
    super_init(self, super(), *args, **kwargs)

class C:
  def __init__(self, *args, **kwargs):
    self.some_num = kwargs['some_num']
    assert self.some_num >= 10
    super_init(self, super(), *args, **kwargs)

class CombinedCba(C, B, A):
  pass

combo_cba = CombinedCba(a='a', b='b', some_num=25)


class CombinedAc(A, C):
  pass

combo_ac = CombinedAc(a='a', some_num=15)

标签: pythonpython-3.x

解决方案


首先,定义AB和正确C使用super

class A:
    def __init__(self, a, **kwargs):
        super().__init__(**kwargs)
        assert a == 'a'
        self.a = a

class B:
    def __init__(self, b, some_num, *args, **kwargs):
        super().__init__(**kwargs)
        self.b = b
        self.some_num = some_num
        assert self.some_num <= 30

class C:
    def __init__(self, some_num, **kwargs):
        super().__init__(**kwargs)
        self.some_num = some_num
        assert self.some_num >= 10

特别是,请注意BC声明“所有权” some_num,而不必担心另一个类可能会使用它。

接下来,定义一个混合类,它只确保some_num用于设置some_num属性。

class SomeNumAdaptor:
    def __init__(self, some_num, **kwargs):
        self.some_num = some_num
        super().__init__(**kwargs)

第三,定义包装器BC获取some_numfrom的值,self以便将其添加回关键字参数(已SomeNumAdaptor剥离):

class CWrapper(C):
    def __init__(self, **kwargs):
        super().__init__(some_num=self.some_num, **kwargs)

class BWrapper(B):
    def __init__(self, **kwargs):
        super().__init__(some_num=self.some_num, **kwargs)

这意味着BC都将“重置” 的值self.num

B(如果您还可以修改并C使其成为some_num可选并检查是否存在,则不需要包装器self.some_num。)

SomeNumAdaptor最后,根据包装类定义您的组合类。SomeNumAdaptor 您必须从first继承,以确保BWrapperCWrapperfindsome_num作为属性,而不管它们的相对顺序如何。

class CombinedAbc(SomeNumAdaptor, A, BWrapper, CWrapper):
    pass


class CombinedCba(SomeNumAdaptor, CWrapper, BWrapper, A):
    pass

combo_cba = CombinedCba(a='a', b='b', some_num=25)
combo_abc = CombinedAbc(a='a', b='b', some_num=15)

以上所有假设既不B也不C将其some_num参数的修改值存储到属性中。如果是这样,您将需要更复杂的包装器来处理它,可能不仅仅是将接收到的值传递给__init__. B请注意,这可能表明同时从两者继承的一个更基本的问题C


推荐阅读