当 Python 数据 class 继承 class 时控制初始化顺序

control initialize order when Python dataclass inheriting a class

我所知道的
Python 数据class 允许继承,数据class 或class。 在最佳实践中(以及其他语言),当我们进行继承时,应该首先调用初始化。在 Python 中是:

def __init__(self):
    super().__init__()
    ...

我在做什么
由于 dataclass 是在 Python 3.7 中引入的,我正在考虑用 dataclass 替换我所有的 classes。 使用数据class,它的好处之一是为您生成__init__。当 dataclass 需要继承基数 class 时,这并不好——例如:

class Base:
    def __init__(self):
        self.a = 1

@dataclass
class Child(Base):
    a:int
    def __post_init__(self):
        super().__init__() 

我的问题
问题是我们必须将超级初始化调用放在 __post_init__ 中,实际上调用 after dataclass 的 init.
缺点是我们失去了约定契约,初始化混乱导致我们无法覆盖 super classes.

的属性。

可以通过__pre_init__的概念来解决。我已经阅读了该文档,但没有发现与该概念有任何关系。我错过了什么吗?

怎么样:

from dataclasses import dataclass


class Base:
    def __init__(self, a=1):
        self.a = a


@dataclass
class Child(Base):

    def __post_init__(self):
        super().__init__()


ch = Child()

实际上在__init__之前调用了一种方法:它是__new__。所以你可以做这样一个技巧:在Child.__new__中调用Base.__init__。我不能说这是一个好的解决方案,但如果您有兴趣,这里有一个工作示例:

class Base:
    def __init__(self, a=1):
        self.a = a


@dataclass
class Child(Base):
    a: int

    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls)
        Base.__init__(obj, *args, **kwargs)
        return obj


c = Child(a=3)
print(c.a)  # 3, not 1, because Child.__init__ overrides a

In best practice [...], when we do inheritance, the initialization should be called first.

这是一个合理的最佳实践,但在数据classes 的特定情况下,它没有任何意义。

调用父构造函数有两个原因,1) 实例化将由父构造函数处理的参数,以及 2) 运行 父构造函数中需要在之前发生的任何逻辑实例化。

Dataclasses 已经为我们处理了第一个:

 @dataclass
class A:
    var_1: str

@dataclass
class B(A):
    var_2: str

print(B(var_1='a', var_2='b'))  # prints: B(var_1='a', var_2='b')
# 'var_a' got handled without us needing to do anything

而第二个不适用于数据classes。其他 classes 可能会在它们的构造函数中做各种奇怪的事情,但 dataclasses 只做一件事:它们将输入参数分配给它们的属性。如果他们需要做任何其他事情(不能由 __post_init__ 处理),你可能正在写一个 class 不应该是数据 class.