首页 > 编程问答 >如何继承(从父类)数据类字段自省功能?

如何继承(从父类)数据类字段自省功能?

时间:2024-07-22 07:05:47浏览次数:10  
标签:python inheritance python-dataclasses python-class

我有一个父数据类,然后各种其他类将扩展该父数据类。我们将这些数据类称为 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=}")

在这个修改后的代码中:

  1. 我们使用 ClassVar 类型提示来表明这些属性属于类级别。
  2. _init_introspection 方法用于初始化内省属性。
  3. 使用 @property 装饰器,在第一次访问内省属性时调用 _init_introspection 方法进行初始化。
  4. 添加了一个 _introspection_initialized 标记,确保初始化只执行一次。

现在,你可以在 ChildDC 类定义完成后访问内省属性,并且它们将包含正确的值。

标签:python,inheritance,python-dataclasses,python-class
From: 78776507

相关文章

  • 一个简单的问题(python、串行通信和arduinos)
    只是一个关于小脚本的快速问题,由于某种原因无法工作我运行了这个脚本:importserialimporttimeimportturtledefserialreading():serialPort=serial.Serial(port="COM5",baudrate=9600,bytesize=8,timeout=2,stopbits=serial.STOPBITS_ONE......
  • 我在 Windows 10 上运行 Python 代码后控制台立​​即关闭
    虽然我在代码末尾使用input(),但在Windows10(IDLE之外)的窗口中输入名称后,控制台仍然立即关闭,并且我看不到结果。我该怎么做才能阻止控制台关闭?#!python3name=input('Enteryourname:')print('Hello'+name)input('pressEntertoexit:')你在代码末尾......
  • 具有未定义嵌套列表深度的嵌套列表的Python注释类型
    [[1,2,3],3,[2,4],5]的类型是list[list[int]|int]但是,如果嵌套列表具有未定义的深度,例如[[[1,2]],2,[1,[3,[3]]]],3,[2,[2]]],那么它会具有什么类型?可以使用递归类型提示来表示任意深度嵌套的列表:fromtypingimportList,Union......
  • 在Spyder(Python 3.6)中导入cv2时出现导入错误
    我已经在Windows操作系统中安装了opencv3.0.0。我已运行该应用程序并已成功将其安装在C:\驱动器中,并且还将cv2.pyd文件复制到C:\Python27\Lib\site-packages中,正如我在几个教程视频中看到的那样在我的Python2.7.5Shell中,即当我键入>>>i......
  • Python + VS Code 调试器:可视化我的程序当前正在执行的源代码中的位置?
    当我使用VSCodePython调试器时:我可以执行我的程序,以便编辑器将我逐行带到源代码中的任何位置(跳转到相关文件/如果尚未打开则将其打开)目前的执行情况是?是的,VSCode的Python调试器可以让你逐行执行代码,并实时显示当前执行的位置。以下是操作方法:1.设置断点:......
  • 如何立即取消使用 Ollama Python 库生成答案的 Asyncio 任务?
    我正在使用Ollama通过OllamaPythonAPI从大型语言模型(LLM)生成答案。我想通过单击停止按钮取消响应生成。问题在于,只有当响应生成已经开始打印时,任务取消才会起作用。如果任务仍在处理并准备打印,则取消不起作用,并且无论如何都会打印响应。更具体地说,即使单击按钮后,此函数......
  • 使用 np.array 索引过滤 Python 列表
    谁能向我解释一下列表self.data如何使用numpy索引数组selec_idx进行索引/过滤?完整的课程可在https://github.com/kaidic/LDAM-DRW/blob/master/imbalance_cifar.pydefgen_imbalanced_data(self,img_num_per_cls):new_data=[]n......
  • 尝试在cmd(python)中安装turtle
    当我在cmd中编写pipinstallturtle后,这条消息出现在我面前。有人知道该怎么办吗?C:\>pipinstallturtleCollectingturtleUsingcachedturtle-0.0.2.tar.gz(11kB)ERROR:Commanderroredoutwithexitstatus1:command:'C:\Users\Bruger\App......
  • Python + Polars:如何有效地“fill_null”仅 DataFrame 的某些列?
    例如,假设我只想fill_null(strategy="zero")DataFrame的数字列。我当前的策略是这样做:final_df=df.select(cs.exclude(cs.numeric()))final_df.with_columns(df.select(cs.numeric()).fill_null(strategy="zero"))是否有替代的、更惯用或更有效的方法来实现我......
  • 如何找到 Windows 上 Python 的安装位置?
    我想找出我的Python在Windows上的安装路径。例如:C:\Python25如何找到Python的安装位置?在Windows上查找Python安装位置的方法有很多种:1.使用where命令(推荐方法):打开命令提示符(cmd)。输入以下命令并按回车键:wherepython......