Python中__str__和__repr__的区别

Python中__str__和__repr__的区别

技术背景

在Python里,__str____repr__ 是两个特殊方法,它们的作用是基于对象的状态返回字符串。不过,它们在用途和设计目标上存在差异。正确理解并运用这两个方法,能让开发者更高效地进行对象的调试、日志记录以及向用户展示信息。

实现步骤

1. 理解默认实现

Python对象默认的 __repr__ 方法类似于如下实现:

1
2
3
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
type(self).__module__, type(self).__qualname__, hex(id(self)))

默认情况下,打印对象时会输出对象所在的模块、类名以及其在内存中的十六进制位置,例如:<__main__.Foo object at 0x7f80665abdd0> 。若未定义 __str__ 方法,__repr__ 会作为后备方法被调用。

2. 实现 __repr__ 方法

__repr__ 的目标是提供对象的明确表示,最好能让 eval(repr(obj)) 重新创建出相同的对象。以 datetime 对象为例:

1
2
3
4
import datetime

today = datetime.datetime.now()
print(repr(today)) # 输出类似 'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'

datetime 对象的 __repr__ 方法实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def __repr__(self):
"""Convert to formal string, for repr()."""
L = [self._year, self._month, self._day, # These are never zero
self._hour, self._minute, self._second, self._microsecond]
if L[-1] == 0:
del L[-1]
if L[-1] == 0:
del L[-1]
s = "%s.%s(%s)" % (self.__class__.__module__,
self.__class__.__qualname__,
", ".join(map(str, L)))
if self._tzinfo is not None:
assert s[-1:] == ")"
s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
if self._fold:
assert s[-1:] == ")"
s = s[:-1] + ", fold=1)"
return s

3. 实现 __str__ 方法

__str__ 的目标是提供对象的易读表示,适用于向用户展示信息。同样以 datetime 对象为例:

1
print(str(today))  # 输出类似 '2012-03-14 09:21:58.130922'

datetime 对象的 __str__ 方法实现如下:

1
2
3
def __str__(self):
"Convert to string, for str()."
return self.isoformat(sep=' ')

4. 自定义类的实现示例

以下是一个自定义 Fraction 类的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Fraction:
def __init__(self, num, den):
self.__num = num
self.__den = den

def __str__(self):
return '(' + str(self.__num) + '/' + str(self.__den) + ')'

def __repr__(self):
return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'


f = Fraction(1, 2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 自定义类实现 __str__ 和 __repr__
class Fraction:
def __init__(self, num, den):
self.__num = num
self.__den = den

def __str__(self):
return '(' + str(self.__num) + '/' + str(self.__den) + ')'

def __repr__(self):
return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'


# 使用示例
f = Fraction(1, 2)
print(str(f)) # 输出 (1/2)
print(repr(f)) # 输出 Fraction (1,2)

最佳实践

  • 为所编写的每个类都实现 __repr__ 方法,这样在开发过程中,开发者就能得到可重现的示例。
  • 当需要对象的人类可读字符串表示时,再实现 __str__ 方法。
  • __repr__ 方法里,使用 %rrepr() 来格式化对象,以保证表示的明确性。

常见问题

1. 默认实现的实用性问题

默认的 __repr__ 实现提供的信息有限,对于调试和对象的明确表示帮助不大。所以,建议为每个类都实现自定义的 __repr__ 方法。

2. __str____repr__ 的调用规则

  • 若调用 print 函数、format 函数、str.format 函数或 str 函数,会优先调用对象的 __str__ 方法;若未定义 __str__ 方法,则调用 __repr__ 方法。
  • 在Python shell中,当计算表达式返回对象时,会调用对象的 __repr__ 方法。

3. 容器的 __str__ 方法

容器(如列表、元组等)的 __str__ 方法会调用其包含对象的 __repr__ 方法,而非 __str__ 方法。这是为了保证容器表示的明确性。例如:

1
2
3
from datetime import datetime
from decimal import Decimal
print((Decimal('52'), datetime.now())) # 输出使用对象的 __repr__

4. eval(repr(obj)) 的使用问题

虽然 eval(repr(obj)) 理论上可重新创建对象,但实际中很少使用,因为 eval 存在安全风险,并且使用字符串序列化对象效率较低。建议使用 pickle 等更安全高效的方法进行对象序列化。


Python中__str__和__repr__的区别
https://119291.xyz/posts/2025-05-09.difference-between-str-and-repr-in-python/
作者
ww
发布于
2025年5月9日
许可协议