繁体   English   中英

在调用 super().__init__ 时,如何判断超级初始化是否是 python3 中的 object.__init__?

[英]When calling super().__init__ how can I tell if the super init is object.__init__ in python3?

给定任意 class inheritance 我如何找出super().__init__ == object.__init__

说明 + 示例

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

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

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

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

我能够完成这项工作的唯一方法是构建一个新的临时 class 包含剩余的超类,然后检查该 class 的__init__方法。

def super_init(self, super_instance, *args, **kwargs):
    classes_in_order = self.__class__.__mro__
    for i, cls in enumerate(classes_in_order):
        if cls == super_instance.__thisclass__:
            remainder_cls = type('_unused', classes_in_order[i+1:], {})
    super_init_is_object_init = remainder_cls.__init__ == object.__init__
    if not super_init_is_object_init:
        super_instance.__init__(*args, **kwargs)

这些尝试没有奏效:

  • 检查super().__init__ == object.__init__不起作用
  • 检查super().__init__ is object.__init__没有工作
  • 检查super(super().__thisclass__, self)object.__init__没有用
  • inspect.signature反省 function 签名不起作用

首先,定义ABC以正确使用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 ,而不必担心另一个 class 可能会使用它。

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

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

第三,为BC定义包装器,它们从self获取some_num的值,以便将其作为关键字参数添加回来( 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的值。

(如果您还可以修改BC以使some_num可选并检查self.some_num的存在,则不需要包装器。)

最后,根据SomeNumAdaptor和包装类定义您的组合类。 您必须首先SomeNumAdaptor继承,以确保BWrapperCWrapper找到some_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)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM