如何从父类实例创建子类实例并正确继承其数据?
如何从父类实例创建子类实例并继承数据?
当你已有父类实例,想要基于它快速创建子类实例并自动继承父类数据,避免手动逐个赋值字段时,可能会遇到类似以下的错误场景:
问题重现
示例代码
from dataclasses import dataclass from typing import Self @dataclass class SuperClass: hello: int world: int @dataclass class ChildClass(SuperClass): kitty: int @classmethod def from_super(cls, s: SuperClass, kitty: int) -> Self: x = cls(s, kitty=kitty) return x
测试代码
super_instance = SuperClass(0, 1) child = ChildClass.from_super(super_instance, 2) print(child)
报错信息
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[48], line 1 ----> 1 ChildClass.from_super(super_instance, 2) Cell In[46], line 15 13 @classmethod 14 def from_super(cls, s: SuperClass, kitty: int) -> Self: ---> 15 x = cls(s, kitty=kitty) 16 return x TypeError: ChildClass.__init__() missing 1 required positional argument: 'world'
错误原因:子类ChildClass的构造函数需要hello、world、kitty三个参数,但直接传入父类实例s会被当作第一个位置参数hello,导致world参数缺失。
解决方案
方法1:使用dataclasses.asdict()转换父类实例为字典
dataclasses.asdict()可以将dataclass实例转为包含所有字段键值对的字典,通过解包字典即可传递父类所有字段值:
from dataclasses import dataclass, asdict from typing import Self @dataclass class SuperClass: hello: int world: int @dataclass class ChildClass(SuperClass): kitty: int @classmethod def from_super(cls, s: SuperClass, kitty: int) -> Self: return cls(**asdict(s), kitty=kitty)
测试运行后输出:ChildClass(hello=0, world=1, kitty=2)
方法2:直接访问实例的__dict__属性
如果dataclass未使用@dataclass(slots=True),可直接通过__dict__获取实例字段的键值对,同样用解包传递:
@classmethod def from_super(cls, s: SuperClass, kitty: int) -> Self: return cls(**s.__dict__, kitty=kitty)
注:若父类启用了slots,__dict__可能不存在,此时推荐使用方法1。
方法3:通过dataclasses.fields精准提取父类字段
如果需要严谨地只传递父类定义的字段(避免带入实例额外属性),可通过dataclasses.fields获取父类字段列表后构建字典:
from dataclasses import dataclass, fields from typing import Self @dataclass class SuperClass: hello: int world: int @dataclass class ChildClass(SuperClass): kitty: int @classmethod def from_super(cls, s: SuperClass, kitty: int) -> Self: super_fields = {f.name: getattr(s, f.name) for f in fields(s)} return cls(**super_fields, kitty=kitty)
内容的提问来源于stack exchange,提问作者bzm3r
相关产品推荐
相关产品推荐

