我有一个父数据类,然后各种其他类将扩展该父数据类。我们将这些数据类称为
DC
在下面的示例代码中,请参阅
ParentDC
和示例
ChildDC
:
from dataclasses import dataclass, field, fields
from typing import Optional
@dataclass
class ParentDC:
type_map: dict[str, type] = field(init=False, metadata={"support": True})
primary_fields: set[str] = field(
init=False, default_factory=set, metadata={"support": True}
)
secondary_fields: set[str] = field(
init=False, default_factory=set, metadata={"support": True}
)
dtype_map: dict[str, type] = field(
init=False, default_factory=dict, metadata={"support": True}
)
def __init_subclass__(cls, type_map: dict[str, type]) -> None:
print(cls.__class__.__qualname__)
cls.type_map = type_map
cls.primary_fields = set()
cls.secondary_fields = set()
field_data = fields(cls)
for fdat in field_data:
if not fdat.metadata.get("support", False):
if fdat.metadata.get("secondary", False):
cls.secondary_fields.add(fdat.name)
else:
cls.primary_fields.add(fdat.name)
cls.dtype_map = {
k: type_map[v].dtype
for k, v in cls.__annotations__.items()
if k in cls.primary_fields.union(cls.secondary_fields)
}
type_map = {
"alpha": int,
"beta": float,
}
@dataclass
class ChildDC(ParentDC, type_map=type_map):
alpha: Optional[str] = field(
default=None, kw_only=True, metadata={"secondary": True}
)
beta: str = field(kw_only=True)
print(f"{ChildDC.primary_fields=}")
print(f"{ChildDC.secondary_fields=}")
print(f"{ChildDC.dtype_map=}")
我想创建一些对所有
DC
通用的“内省功能”。此自省功能位于
类
级别:您不需要创建
实例
ChildDC
即可访问哪些字段是其主要字段等。
目前的代码不起作用:
type
ChildDC.primary_fields=set()
ChildDC.secondary_fields=set()
ChildDC.dtype_map={}
而且我对为什么有一些暗示:何时
__init_subclass__
是生成和存储此类内省数据的错误位置,因为父级无权访问任何子级在
__init_subclass__
.
应该在哪里生成和可视化这种内省信息?
你对
__init_subclass__
时机的理解是正确的。当
ParentDC.__init_subclass__
被调用时,
ChildDC
类定义还没有完成,因此无法访问
ChildDC
的字段信息。
为了解决这个问题,你可以将字段信息的生成延迟到子类定义完成后。一种方法是在第一次访问内省属性时动态生成它们。
from dataclasses import dataclass, field, fields
from typing import Optional, ClassVar
@dataclass
class ParentDC:
type_map: ClassVar[dict[str, type]] = field(init=False)
primary_fields: ClassVar[set[str]] = field(init=False)
secondary_fields: ClassVar[set[str]] = field(init=False)
dtype_map: ClassVar[dict[str, type]] = field(init=False)
def __init_subclass__(cls, type_map: dict[str, type]) -> None:
cls.type_map = type_map
# 移除初始化逻辑
@classmethod
def _init_introspection(cls):
"""初始化内省属性."""
if hasattr(cls, '_introspection_initialized'):
return
cls.primary_fields = set()
cls.secondary_fields = set()
field_data = fields(cls)
for fdat in field_data:
if not fdat.metadata.get("support", False):
if fdat.metadata.get("secondary", False):
cls.secondary_fields.add(fdat.name)
else:
cls.primary_fields.add(fdat.name)
cls.dtype_map = {
k: cls.type_map[v].dtype
for k, v in cls.__annotations__.items()
if k in cls.primary_fields.union(cls.secondary_fields)
}
cls._introspection_initialized = True # 标记已初始化
@property
def all_fields(self):
self._init_introspection()
return self.primary_fields.union(self.secondary_fields)
# 为其他内省属性添加类似的 @property 装饰器
type_map = {
"alpha": int,
"beta": float,
}
@dataclass
class ChildDC(ParentDC, type_map=type_map):
alpha: Optional[str] = field(
default=None, kw_only=True, metadata={"secondary": True}
)
beta: str = field(kw_only=True)
print(f"{ChildDC.primary_fields=}")
print(f"{ChildDC.secondary_fields=}")
print(f"{ChildDC.dtype_map=}")
print(f"{ChildDC.all_fields=}")
在这个修改后的代码中:
-
我们使用
ClassVar
类型提示来表明这些属性属于类级别。 -
_init_introspection
方法用于初始化内省属性。 -
使用
@property
装饰器,在第一次访问内省属性时调用_init_introspection
方法进行初始化。 -
添加了一个
_introspection_initialized
标记,确保初始化只执行一次。
现在,你可以在
ChildDC
类定义完成后访问内省属性,并且它们将包含正确的值。