python 数据类 `__init_subclass__` 不从子类加载字段

python dataclass `__init_subclass__` does not load the fields from subclass

请检查下面的代码

import dataclasses


@dataclasses.dataclass
class A:
    a: int = 10

    def __init_subclass__(cls, **kwargs):
        for f in dataclasses.fields(cls):
            print("     ", cls, f.name)


print("Defining Subclass B")


@dataclasses.dataclass
class B(A):
    b: int = 100


print("Defining Subclass C")


@dataclasses.dataclass
class C(B):
    c: int = 1000

输出为

Defining Subclass B
      <class '__main__.B'> a
Defining Subclass C
      <class '__main__.C'> a
      <class '__main__.C'> b

我期待

Defining Subclass B
      <class '__main__.B'> a
      <class '__main__.B'> b
Defining Subclass C
      <class '__main__.C'> a
      <class '__main__.C'> b
      <class '__main__.C'> c

显然 dunder 方法 __init_subclass__ 还没有子类中字段的概念,因为它没有被加载。请让我知道如何获得预期的输出。

因此,装饰器的工作方式如下:

@some_decorator
class A:
    pass

相当于:

class A:
   pass
A = some_decorator(A)

因此,dataclass 装饰器 __dataclass_fields__ 属性添加到 class 对象 时没有 运行 __init_subclass__ 运行s,因为已经创建了整个 class 个对象。

可以 手动检查 __annotations__ (无论如何 dataclass 都依赖于创建 field 对象)。请注意,您将必须手动检查 MRO 中的所有 classes,注意以相反的顺序进行检查并防止可能缺少注释的 classes,例如:

import dataclasses


@dataclasses.dataclass
class A:
    a: int = 10

    def __init_subclass__(cls, **kwargs):
        for klass in  reversed(cls.mro()):
            # in case a base class lacks annotations, e.g. object
            annotations = getattr(klass, '__annotations__', {})
            for name, value in annotations.items():
                print("     ", cls, name, value)

print("Defining Subclass B")


@dataclasses.dataclass
class B(A):
    b: int = 100


print("Defining Subclass C")


@dataclasses.dataclass
class C(B):
    c: int = 1000

可能适合你。

上面为我打印了以下输出:

Defining Subclass B
      <class '__main__.B'> a <class 'int'>
      <class '__main__.B'> b <class 'int'>
Defining Subclass C
      <class '__main__.C'> a <class 'int'>
      <class '__main__.C'> b <class 'int'>
      <class '__main__.C'> c <class 'int'>