该用类封装返回值当需携带行为(如校验、链式调用)或字段语义固定且随业务演进;否则优先 namedtuple、dataclass 或 dict。

什么时候该用类封装返回值,而不是字典或命名元组
当返回的数据结构需要携带行为(比如校验、转换、链式调用),或者多个函数共用同一套字段语义且字段会随业务演进时,才值得上类。纯数据容器用 dict 或 namedtuple 更轻量、更易调试。
- 字段含义固定、不常变?优先
namedtuple或dataclass(无方法) - 返回值要支持
.to_json()、.is_valid()这类操作?上类 - 下游频繁做
if res.status == "success": ...判断?加属性方法比重复写条件更安全 - 你正在写 SDK 或对外 API 封装?类能提供明确接口契约,避免字段名拼错没人提醒
dataclass vs 普通 class:选哪个封装返回结果
dataclass 适合字段多、逻辑少、强调可读性和序列化的场景;普通 class 适合需要精细控制初始化、隐藏内部状态、或重载运算符的场景。
-
dataclass默认生成__init__、__repr__、__eq__,省事但不可控;加unsafe_hash=True才能当字典 key,别忘了设 - 想让某个字段只读?用
field(default=..., init=False)+@property,别直接赋值 - 普通
class初始化里做参数校验更自然,比如if not url.startswith("https://"):抛ValueError -
dataclass序列化到 JSON 需手动处理(asdict()或自定义__dict__),普通 class 可以直接加to_dict()方法
返回对象里放方法,会不会影响性能或测试
会,但通常不明显——真正拖慢的是方法里做的事,不是“有方法”这个事实。问题出在误用:比如在 __init__ 里发起 HTTP 请求,或把数据库连接塞进返回对象里。
- 方法必须是纯函数式或只读的(比如
.formatted_time()),否则调用方无法预料副作用 - 测试时如果方法依赖外部服务,得 mock,不如把行为拆到单独函数里(如
format_time(dt)),对象只存原始数据 - 返回对象被大量创建(如每秒万级日志解析)?避免在
__post_init__做字符串拼接或正则匹配 - 用
__slots__ = ("id", "name", ...)能省内存,但仅当字段极其固定且实例极多时才值得加
常见踩坑:把 dict 当对象用,又偷偷改字段
最典型的是函数返回 {"user_id": 123, "name": "Alice"},下游直接 res["name"] = res["name"].strip() —— 看似省事,实则破坏了返回值的不可变契约,后续有人加缓存或日志就崩。
立即学习“Python免费学习笔记(深入)”;
- 用
types.SimpleNamespace替代裸 dict,至少能用点号访问:res.name,还能防止意外覆盖(没__setitem__) - 真要可变,显式声明意图:返回
MutableResult类,别让调用方猜 - API 响应解析后立刻转成不可变结构(
dataclass(frozen=True)或NamedTuple),别留着 dict 流窜全栈 - Pydantic
BaseModel是个折中方案:自动校验 + 字段提示 +.model_dump(),但启动开销略大,别在热路径里用










