为Identity类添加classmethod后JSON序列化报错的排查与解决
问题根源
你写的to_json是类方法,里面传给json.dumps的是cls(即Identity类本身),但你的BasicEncoder原本是用来序列化类的实例对象的。类本身的__dict__是mappingproxy类型(存储类属性的只读映射),不是实例的普通字典,所以会抛出'mappingproxy' object has no attribute '__dict__'错误。另外,序列化类时会遍历类级别的成员(比如类方法、属性描述符),这就导致了'getset_descriptor' object has no attribute '__dict__'这类异常。
解决方案
方案1:将to_json改为实例方法(最直接)
把类方法改成实例方法,操作当前实例而非类本身,同时优化编码器,只处理Identity实例:
from __future__ import annotations import json from typing import Any class Identity: def __init__(self, name: str) -> None: self.name = name self.permissions = [] # 改成实例方法,操作self(当前实例) def to_json(self) -> str: return json.dumps(self, cls=BasicEncoder) class BasicEncoder(json.JSONEncoder): def default(self, obj: Any) -> Any: # 只处理Identity实例,避免其他类型误操作 if isinstance(obj, Identity): return { "name": obj.name, "permissions": obj.permissions } # 其他类型交给父类处理 return super().default(obj) id = Identity(name='Random name') print(id.to_json())
方案2:保留类方法,但传入实例参数
如果一定要用类方法,需要让方法接收要序列化的实例作为参数:
from __future__ import annotations import json from typing import Any class Identity: def __init__(self, name: str) -> None: self.name = name self.permissions = [] @classmethod def to_json(cls, instance: Identity) -> str: return json.dumps(instance, cls=BasicEncoder) class BasicEncoder(json.JSONEncoder): def default(self, obj: Any) -> Any: if isinstance(obj, Identity): return obj.__dict__ return super().default(obj) id = Identity(name='Random name') # 调用时传入实例 print(Identity.to_json(id))
方案3:使用dataclass简化序列化(Python 3.7+)
用dataclass可以省去手动处理__dict__的麻烦,借助asdict快速转换为可序列化的字典:
from __future__ import annotations import json from dataclasses import dataclass, asdict @dataclass class Identity: name: str permissions: list = None # 初始化默认空列表 def __post_init__(self): if self.permissions is None: self.permissions = [] def to_json(self) -> str: return json.dumps(asdict(self)) id = Identity(name='Random name') print(id.to_json())
内容的提问来源于stack exchange,提问作者lapots
相关产品推荐
相关产品推荐

