Python不使用继承如何让子数据类访问父类实例的get_conn方法
方案实现
核心思路
放弃不稳定的inspect/traceback调用栈分析方案,采用工厂方法+Pydantic原生私有属性实现,完全不修改数据类原有__init__逻辑,也不依赖继承,适配你要求的调用习惯。
1. 关联Parent与子数据类的具体实现
借助Pydantic的PrivateAttr定义私有字段存储Parent实例引用,该字段不会被纳入数据类的参数校验、序列化逻辑,完全不影响原有数据类的使用。
再通过Parent类的__getattr__方法做动态分发,调用parent.Child()时自动将当前Parent实例注入到生成的子实例私有属性中。
示例代码如下:
from abc import ABC from functools import partial from pydantic import PrivateAttr from pydantic.dataclasses import dataclass from cached_property import cached_property # 原有Base基类 class Base(ABC): @cached_property def _conn(self): raise NotImplementedError def get_conn(self): return self._conn # 原有Parent类 class Parent(Base): @cached_property def _conn(self): # 你的专属客户端生成逻辑,仅会执行一次 print("仅拉取一次凭证") return "认证客户端实例" def __getattr__(self, name): # 注册所有要关联的子数据类 dataclass_map = { "Child": Child, "Toy": Toy } if name in dataclass_map: # 返回绑定了当前Parent实例的构造器 return partial(self._wrap_dataclass, dataclass_map[name]) raise AttributeError(f"'Parent' object has no attribute '{name}'") def _wrap_dataclass(self, cls, *args, **kwargs): instance = cls(*args, **kwargs) # 自动注入Parent实例到子实例私有属性 instance._parent = self return instance # 子数据类,无需继承Parent @dataclass class Child: name: str age: int # Pydantic私有属性,不会参与参数校验、序列化 _parent: Parent = PrivateAttr() def get_favorite_toy(self): # 用当前实例绑定的Parent构造Toy,自动继承连接 return self._parent.Toy(name="乐高", color="红色") @dataclass class Toy: name: str color: str _parent: Parent = PrivateAttr() def get_color(self): # 直接调用Parent的公共方法 conn = self._parent.get_conn() print(f"使用连接 {conn} 执行逻辑") return self.color
2. 链路连通性验证
完全符合你期望的调用方式,所有子实例、子实例生成的其他子实例都共享同一个Parent的连接:
if __name__ == "__main__": parent = Parent() # 按理想方式创建Child实例 child = parent.Child(name="小明", age=8) # 首次调用才初始化连接,仅执行一次 print(child._parent.get_conn()) # 输出:仅拉取一次凭证 \n 认证客户端实例 # Child方法返回的Toy实例自动绑定同一个Parent toy = child.get_favorite_toy() print(toy.get_color()) # 输出:使用连接 认证客户端实例 执行逻辑 \n 红色
方案优势
- 完全兼容Pydantic dataclass的特性,不需要修改
__init__方法,不影响原有数据类的校验、序列化逻辑 - 连接仅初始化一次,全局复用,不会重复拉取凭证
- 无黑魔法依赖,稳定性远高于调用栈分析方案
- 所有子实例链路自动绑定同一个Parent实例,不需要手动注入参数
内容的提问来源于stack exchange,提问作者hamzaahmad
相关产品推荐
相关产品推荐

