结论:__str__用于用户友好的可读输出,__repr__用于开发者调试的精确还原;应重写__repr__以避免内存地址显示,确保关键字段清晰、可执行、无歧义,且不触发副作用。

直接说结论:用 __str__ 控制 print() 和 str() 的可读输出,用 __repr__ 保证 repr()、交互式环境回显、日志记录时能还原对象状态——二者不互斥,但目标完全不同。
什么时候该重写 __repr__?
当你在调试时看到类似 <User object at 0x7f8a1c2b3e50> 这种信息,就说明 __repr__ 没提供有效线索。它本该像调试器的“快照”:包含关键字段、可执行、尽量无歧义。
- 理想形式是返回一个能直接
eval()构造出等价对象的字符串(如User(name="alice", age=30)),但现实中只要字段明确、不含内存地址即可 - 避免返回空字符串、
"<class>" </class>这类无意义内容 - 如果类有不可序列化的属性(比如文件句柄、线程锁),跳过它们,只保留核心数据字段
- 在
__repr__中调用repr()包裹字段值(如repr(self.name)),确保引号、转义符正确显示
为什么 __str__ 不该和 __repr__ 一样?
因为用户场景不同:__str__ 面向终端用户或日志阅读者,要简洁、自然语言化;__repr__ 面向开发者,要精确、结构化。强行复用会导致 print 输出冗长难读,或调试时丢失关键字段。
-
__str__可以省略技术性字段(如 id、created_at),只留业务相关描述(如"Alice (30 years old)") - 不要在
__str__中返回带引号的字符串或括号包裹结构,那会干扰可读性 - 若类没有明确“用户视角”,干脆不实现
__str__,让 Python 自动 fallback 到__repr__ - 注意:Jupyter notebook 的单元格最后一行表达式默认调用
__repr__,不是__str__
常见错误:用 f-string 直接拼接未转义字段
比如写成 f"User({self.name}, {self.age})" 看似方便,但当 self.name = "O'Connor" 时,输出变成 User(O'Connor, 30) —— 这无法被 eval() 解析,也容易在日志中引发解析错误。
立即学习“Python免费学习笔记(深入)”;
- 正确做法是用
repr(self.name)得到'O\'Connor',再拼入 - 更稳妥的是用
!r格式符:f"User({self.name!r}, {self.age!r})" - 对嵌套对象(如
self.profile),别直接repr(self.profile),除非确认其__repr__是可靠的;否则提取必要字段手动构造 - 避免在
__repr__中触发副作用(如访问数据库、调用耗时方法),它可能被日志系统频繁调用
真正难的不是写这两个方法,而是判断哪些字段算“关键”、哪些属于“内部实现细节”。每次修改类结构后,记得同步审视 __repr__ 是否仍反映真实状态——它是最常被忽略却最影响调试效率的接口之一。


















