Python 中 __str__ 与 __repr__ 方法的区别与调用机制详解
本文深入解析 Python 中 __str__ 和 __repr__ 两个魔术方法的定义与调用时机。通过对比内置类型与自定义类的行为,阐明 repr 作为正式表示在调试和交互环境中的优先级,以及 str 在用户友好输出中的作用。文章还探讨了当仅定义其中一个方法时的回退机制,以及字符串格式化、print 和调试器显示的具体调用逻辑,帮助开发者正确实现对象的可读性与可重现性。
引言:__str__ 与 __repr__ 的基本概念
在阅读关于将对象转换为字符串的章节时,接触到了 repr 函数。为了在深入掌握 Python 面向对象编程之前建立直观认知,这里从感性角度梳理 repr 与 str 这两个函数的核心区别。
Python 的全局函数 repr 和 str 分别映射到对象的 __repr__ 和 __str__ 方法调用。此外,当执行 str(obj) 或 print(obj) 操作时,以及在进行 Python 代码调试以查看对象状态时,系统会优先调用哪个方法?这正是本文旨在验证的关键点。
类比 Java 中 System.out.println(obj) 或字符串拼接 "hello" + obj 都会触发调用 Java 对象的 toString() 方法,我们需要探究 Python 中对应的机制是如何运作的。
官方定义:正式表示与非正式表示
参考某本 Python 入门书籍对 repr 和 str 的解释:
- repr: 提供 Python 对象的正式字符串表示形式(formal string representation)。
- str: 提供 Python 对象的非正式字符串表示形式(informal string representation),即可打印的字符串表示。
从字面含义来看, repr 代表“表示(representation)”,分为正式与非正式两种。表面上看,repr 似乎比 str 更为重要,因为它提供了更精确的对象信息。
内置类型的行为分析
对于 Python 内置对象,我们可以使用 repr、print 和 str 等函数进行转换。以 list 类型为例,其行为如下:
>>> repr([1,2])
'[1, 2]'
>>> print([1,2])
[1, 2]
>>> str([1,2])
'[1, 2]'
自定义类实验:仅定义 __str__ 的情况
然而,上述三个内置函数具体调用了 list 类的哪个内部方法并不直观。为了清晰说明这一点,定义一个自定义类进行实验是最有效的方式。测试环境为 IntelliJ IDEA,以下调试截图展示了 __str__ 和 __repr__ 几种不同定义组合下的表现。
情况一:仅定义了 __str__ 方法。

说明:在仅定义了 __str__ 方法的情况下:
- 调试器在代码行内显示对象时,展示的是
__str__的输出结果;但在变量窗口中查看变量详情时,显示的是默认的__repr__输出结果。 - 函数
repr始终坚持调用默认的__repr__方法,即使未显式定义。 - 函数
str转型操作明确调用了对象的__str__方法。 - 函数
print调用了对象的__str__方法。
自定义类实验:仅定义 __repr__ 的情况
情况二:仅定义了 __repr__ 方法。

说明:在仅定义了 __repr__ 方法的情况下,可以看出 __repr__ 方法具有极高的优先级。它“垄断”了大部分调用场景,包括 repr、str 和 print 函数,甚至 IntelliJ 的调试显示也必须以 __repr__ 方法为核心。
- 在上述所有情况下,系统最终都调用了 __repr__ 方法,没有其他选择。
自定义类实验:同时定义两种方法
情况三:同时定义了 __repr__ 和 __str__ 方法。

说明:在同时定义了 __repr__ 和 __str__ 方法的情况下,__str__ 方法反而能“扳回一局”。除了明确的 repr 会调用 __repr__ 方法,以及调试时变量窗口中显示对象会调用 __repr__ 方法外,其他大多数场景下 __str__ 占优。具体表现如下:
- 使用 函数及 IntelliJ 调试时变量窗口显示变量,均调用 __repr__ 方法。
- IntelliJ 调试时行内显示变量,调用了 __str__ 方法。
- 执行 转型操作时,调用了对象的 __str__ 方法。这不能简单解释为“非正式”,而是用户友好的输出。
- 使用 打印对象时,调用 __str__ 来获取对象的输出字符串。
字符串格式化与拼接的特殊处理
另外,在格式化字符串时调用的对象方法与 print 时一致,例如以下格式化代码:
f1 = "%s" % t
f2 = "{}".format(t)
Python 不会像 Java 那样自动将字符串与对象进行拼接(即 Python 不知道像 Java 那样由字符串加上一个对象)。
"this is " + t #Java 中会展开为 "this is " + t.toString()
Python 会报以下错误:
TypeError: can only concatenate str (not "Test") to str
这表明这里的 + 号只能连接两个字符串。除非定义了 __add__ 和 __radd__ 方法,其对应关系分别为:
t = Test()
z1 = 'hello' + t #相当于 t.__radd__('hello')
z2 = t + 'hello' #相当于 t.__add__('hello')
Python 的 __xyz__ 机制也颇具特色。
以上就是 Python 的 __str__ 和 __repr__ 方法对比的详细内容,更多关于 Python __str__ 和 __repr__ 的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













