自定义__dict__方法触发mypy类型错误?代码问题解析
错误原因与问题分析
1. mypy错误原因
__dict__是Python中object类的只读属性,类型为dict[str, Any],用于存储实例的属性键值对。你将它定义成了方法,这就和父类的属性签名完全不兼容——mypy会严格检查子类对父类成员的重写是否符合类型规范,因此触发"Signature of "dict" incompatible with supertype "object""错误。
2. 运行不符合预期的原因
JSON序列化(比如json.dumps())在处理对象时,会尝试读取对象的__dict__属性来获取可序列化的字段。但你把__dict__改成了方法,序列化时要么拿到的是方法对象(无法序列化),要么你在方法里返回了错误的结构,导致结果不符合预期。
修复方案
不要重载__dict__属性,改用以下几种标准方式实现自定义JSON序列化:
方案1:使用__getstate__方法
Python的json模块在序列化对象时,会优先调用__getstate__方法获取对象的可序列化状态,返回的字典会被直接用于序列化。
方案2:自定义__json__方法 + 自定义编码器
如果需要更明确的序列化逻辑,可以自定义__json__方法,再配合JSONEncoder子类来自动调用它。
方案3:使用dataclasses模块(推荐)
如果你的类是数据类,使用dataclasses.asdict()可以直接将实例转为字典,无需手动处理。
代码示例
错误代码示例
import json class RepeatedValue: def __init__(self, value: int, count: int): self.value = value self.count = count # 错误:把__dict__定义成了方法 def __dict__(self) -> dict[str, int]: return {"value": self.value, "total": self.value * self.count} # 运行时问题:json.dumps会尝试读取__dict__属性,而非调用方法 rv = RepeatedValue(5, 3) print(json.dumps(rv)) # 运行报错或结果不符合预期 # mypy检查会触发Signature错误
修复方案1:使用__getstate__
import json class RepeatedValue: def __init__(self, value: int, count: int): self.value = value self.count = count def __getstate__(self) -> dict[str, int]: return {"value": self.value, "total": self.value * self.count} rv = RepeatedValue(5, 3) print(json.dumps(rv)) # 输出: {"value": 5, "total": 15} # mypy检查无错误
修复方案2:自定义编码器 + __json__
import json class RepeatedValue: def __init__(self, value: int, count: int): self.value = value self.count = count def __json__(self) -> dict[str, int]: return {"value": self.value, "total": self.value * self.count} class CustomEncoder(json.JSONEncoder): def default(self, obj): if hasattr(obj, '__json__'): return obj.__json__() return super().default(obj) rv = RepeatedValue(5, 3) print(json.dumps(rv, cls=CustomEncoder)) # 输出: {"value": 5, "total": 15}
修复方案3:使用dataclasses
import json from dataclasses import dataclass, asdict @dataclass class RepeatedValue: value: int count: int # 自定义序列化逻辑 def to_dict(self) -> dict[str, int]: base = asdict(self) base["total"] = self.value * self.count return base rv = RepeatedValue(5, 3) print(json.dumps(rv.to_dict())) # 输出: {"value": 5, "count": 3, "total": 15}
内容的提问来源于stack exchange,提问作者Joaquín Ruiz
相关产品推荐
相关产品推荐

