如何在继承链中创建嵌套的 __init__ 函数?

How to create nested __init__ functions in a inheritance chain?

我正在尝试实现继承系统,其中 child class 会向他从 ansister 那里收到的字典添加一个值。

例如:

class First:
    specificator = {'first':1}
    inherited_specificator = {}
    def __init__(self, *args, **kwargs):
        ???

class Second(First):
    specificator = {'second':2}

class Third(Second):
    specificator = {'third':3}        

所以我希望我可以实现第三个 class 实例的初始化方法 inherited_specificator = {'first':1, 'second':2, 'third':3}

我尝试过的:

创建将要调用的 init 方法 parent 将要调用的 init 方法...等等,以收集来自所有顶级 classes.

的说明符
class First:
    specificator = {'first':1}
    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        if not getattr(self, 'inherited_specificator ', None): setattr(self, 'inherited_specificator', {})
        self.inherited_specificator = {**self.inherited_specificator , **self.specificator}

但是由于某种原因它对我不起作用,Third().inherited_specificator 等于 {'third':3}。也许我不完全理解 super() 方法的工作方式,但我无法找到有关我的案例的详细信息。

我还尝试创建 set_specificator 函数,该函数将从 init 调用,并且应该在其中将当前 class 说明符添加到继承的说明符,但出现了同样的问题,我得到的只是 {'third':3}.

我的情况有解决办法吗?提前致谢。

更新:
如果可能的话,我正在寻找不覆盖 init 方法的解决方案

看来这就是你想要的:

class First:
  def __init__(self):
    self.specificator = {'first':1}

class Second(First):
  def __init__(self):
    super().__init__()
    self.specificator['second'] = 2

class Third(Second):
  def __init__(self):
    super().__init__()
    self.specificator['third'] = 3

然后就是输出:

> f = First()
> s = Second()
> t = Third()
 
> f.specificator
{'first': 1}
> s.specificator
{'first': 1, 'second': 2}
> t.specificator
{'first': 1, 'second': 2, 'third': 3}

请注意,不必按此顺序执行此操作;我只是为了演示而做的。你仍然可以这样做:

> t = Third()
> t.specificator
{'first': 1, 'second': 2, 'third': 3}

包括参数的继承,隔离在一个inherited_specificator:

from copy import copy

class First:
    def __init__(self, *args, **kwargs):
        print(" > called First.__init__()")
        self.specificator = {"first": 1}
        print("specificator: %s" % self.specificator)
        print(" < end First.__init__()")

class Second(First):
    def __init__(self, *args, **kwargs):
        print(" > called Second.__init__()")
        super().__init__(self)
        self.inherited_specificator = copy(self.specificator)
        self.specificator["second"] = 2
        print("inherited_specificator: %s" % self.inherited_specificator)
        print("specificator: %s" % self.specificator)
        print(" < end Second.__init__()")

class Third(Second):
    def __init__(self, *args, **kwargs):
        print(" > called Third.__init__()")
        super().__init__(self)
        self.inherited_specificator.update(self.specificator)
        self.specificator = {"third": 3}
        print("inherited_specificator: %s" % self.inherited_specificator)
        print("specificator: %s" % self.specificator)
        print(" < end Third.__init__()")

obj = Third()

给出输出:

 > called Third.__init__()
 > called Second.__init__()
 > called First.__init__()
specificator: {'first': 1}
 < end First.__init__()
inherited_specificator: {'first': 1}
specificator: {'first': 1, 'second': 2}
 < end Second.__init__()
inherited_specificator: {'first': 1, 'second': 2}
specificator: {'third': 3}
 < end Third.__init__()

您可以遍历方法解析顺序 (MRO),检查每个 class 是否有可用于更新 inherited_specificatorspecificator 属性。您可能希望以相反的顺序进行迭代,以便子 classes 可以覆盖继承的值。

class First:
    specificator = {'first':1}

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.inherited_specificator = {}
        for s in reversed(type(self).mro()):
            try:
                self.inherited_specificator.update(s.specificator)
            except AttributeError:
                pass


class Second(First):
    specificator = {'second':2}


class Third(Second):
    specificator = {'third':3}


t = Third()
print(t.inherited_specificator)

MRO 的这种手动遍历是必要的,因为每个实例只会调用一个 __init__。该调用只会看到传递给该调用的实际实例的 specificator 属性:没有 FirstSecond 的“中间”实例将在其上调用 First.__init__Third 的实际实例传递给 First.__init__.

之前

或者,您可以使 inherited_specificator 成为 class 属性(在我看来这更有意义)而不是实例属性,并使用 __init_subclass__ 定义它(当class 是定义的,而不是在实例化时定义的。

class Specification:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)

        cls.inherited_specificator = \
           getattr(cls, 'inherited_specificator', {})\ 
           | getattr(cls, 'specificator', {})


class First(Specification):
    specificator = {'first':1}


class Second(First):
    specificator = {'second':2}


class Third(Second):
    specificator = {'third':3}

这里的关键是我们(尝试)在创建新的 class 自己的值之前访问 inherited_specificator 的继承值,这将是继承值和class 的 specificator 属性的值(如果已定义)。

我正在使用 Python 3.9 中引入的新字典合并运算符。在早期版本中,使用类似

def __init_subclass__(cls, **kwargs):
    super().__init_subclass__(**kwargs)
    inherited = getattr(cls, 'inherited_specificator', {})
    d = cls.inherited_specificator = {}
    new_values = getattr(cls, 'specificator', {})
    d.update(**inherited, **new_values)