__str__面向用户,应简洁可读、体现业务语义;__repr__面向开发者,需无歧义、尽可能可复现,用于调试、日志和测试。

重写 __str__ 和 __repr__ 不是为了“看起来更漂亮”,而是为了让对象在不同上下文中被正确、无歧义地呈现——__str__ 面向人,__repr__ 面向开发者和调试器。
什么时候该用 __str__?
当对象被 print()、str() 或字符串格式化(如 f"{obj}")调用时,Python 会找 __str__。它的输出应该简洁、可读、带语义,不暴露内部实现细节。
- 避免返回空字符串或纯类型名(如
"<myclass object at>"</myclass>),那是__repr__的默认行为,不是__str__的职责 - 不要包含内存地址、哈希值等调试信息
- 如果类表示一个业务实体(比如
User),优先返回有意义的业务字段:f"User(name='{self.name}', email='{self.email}')"是__repr__风格;而__str__可以是f"{self.name} <{self.email}>" - 注意编码安全:如果字段可能为
None或含特殊字符,做基础处理,比如str(self.name or 'N/A')
为什么 __repr__ 必须尽可能“可复现”?
Python 的交互式解释器、logging、pprint、异常 traceback 都默认调用 __repr__。它本质是“开发者的接口”——理想情况下,返回的字符串应能直接粘贴进 Python 解释器并重建该对象(至少语义上接近)。
- 必须返回字符串(不能是
None或其他类型),否则会触发TypeError: __repr__ returned non-string (type NoneType) - 字段顺序建议与
__init__参数一致,方便一眼对应:def __init__(self, name, age): ...→__repr__返回f"Person(name={self.name!r}, age={self.age})" - 用
!r格式化字符串内嵌字段,确保引号、转义符等被正确包裹(self.name是"O'Reilly",{self.name!r}就是"'O\'Reilly'") - 复杂对象(如含列表、嵌套对象)不必强求 100% 可 eval,但至少保证关键字段完整、无歧义、不截断
__repr__ 没写好会导致哪些实际问题?
最常见的是日志混乱、调试困难、测试断言失败——尤其在使用 assert obj1 == obj2 但没定义 __eq__ 时,报错信息里全是 <__main__.MyClass object at 0x...>,根本看不出两个对象差在哪。
立即学习“Python免费学习笔记(深入)”;
- 单元测试中,
assertEqual(obj, expected_obj)失败时,diff 显示的是__repr__结果;如果它只返回"MyClass()",你无法判断是哪个字段不匹配 - 在 Jupyter 中,变量最后一行自动显示
__repr__;如果返回过长或含控制字符,会破坏 notebook 渲染 - 用
dataclass时,默认生成的__repr__很规范,但若手动重写却漏掉某个字段,就可能掩盖数据不一致问题 - 某些 ORM(如 SQLAlchemy)依赖
__repr__做调试输出,字段缺失会导致误判对象状态
一个安全、可维护的模板写法
别硬背规则,用这个结构起步:
def __repr__(self):
attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
return f"{self.__class__.__name__}({attrs})"
<p>def <strong>str</strong>(self):</p><h1>选 1–2 个最能代表业务身份的字段</h1><pre class='brush:python;toolbar:false;'>return f"{self.name} (ID: {self.id})" if hasattr(self, 'name') else super().__str__()</pre>注意:self.__dict__.items() 不包含属性(property)、描述符或动态计算字段,所以生产环境建议显式列出关键字段,而不是盲目遍历 __dict__。真正容易被忽略的是:当父类已有 __repr__ 且子类只是加了几个字段时,很多人直接覆盖却不调用 super().__repr__(),结果丢失父类状态——这种继承场景下,要么显式拼接,要么重构为组合模式。


















