__str__和__repr__的目的是什么?

93

我真的不理解Python中的__str____repr__在哪里使用。我的意思是,我明白__str__返回对象的字符串表示形式。但是,我为什么需要它?在什么情况下使用?此外,我还了解了__repr__的用法。

但我不理解的是,我在哪里可以使用它们?


9
在Python中,str()和repr()都是将对象转换为字符串的函数。str()返回人类可读的字符串,而repr()返回可被Python解释器理解的字符串。通常情况下,repr()返回的字符串可以通过eval()函数重新生成该对象,而str()返回的字符串则不能。具体来说,str()用于将对象转换为适合用户阅读的字符串,例如将数字转换为十进制字符串。而repr()则用于将对象转换为Python代码字符串,以便能够恢复原始对象。例如,对于整数1,str(1)返回"1",而repr(1)返回'1'。另外一个例子,对于包含一个列表的列表[[1,2,3], [4,5,6]],str()方法将它转换为"[ [1, 2, 3], [4, 5, 6] ]",而repr()方法将其转换为"[[1, 2, 3], [4, 5, 6]]"。在大多数情况下,如果你只需要将一个对象转换为字符串并打印出来,那么使用str()即可。如果你需要调试或者还原一个对象,那么使用repr()会更加方便。 - miku
5
对于任何来自 Ruby 的人,简而言之就是:__str__ 相当于 to_s__repr__ 相当于 inspect - Ajedi32
3
这回答解决了你的问题吗?__str__和__repr__之间的区别? __str__方法返回一个易于阅读的对象表示形式,通常用于打印和展示。 __repr__方法返回一个唯一的Python表达形式,通常用于调试和开发。 - xiaoou wang
8个回答

90

__repr__

被内置函数repr()和字符串转换(反引号)调用,用于计算对象的“官方”字符串表示。如果可能的话,这应该看起来像一个有效的Python表达式,可以在适当的环境下用于重新创建具有相同值的对象。

__str__

被内置函数str()print语句调用,用于计算对象的“非正式”字符串表示。

如果您有一个类,并且希望每当将此对象作为字符串的一部分使用时获得信息性/非正式输出,请使用__str__。例如,您可以为Django模型定义__str__方法,然后在Django管理界面中呈现。相比于某些像<Model object>这样的东西,您会得到人的名字、事件的名称和日期等信息。


__repr____str__很相似,有时甚至相等(例如标准库中sets.py文件的BaseSet类的示例):

def __repr__(self):
    """Return string representation of a set.

    This looks like 'Set([<list of elements>])'.
    """
    return self._repr()

# __str__ is the same as __repr__
__str__ = __repr__

当我运行代码并尝试理解时,return self._repr() 的作用是什么?它表示 __repr__() 函数只接受一个参数。 - shining
那么,在 Django 中我可以使用 __repr__ 代替 __str__ 吗? - Amit Tripathi

69

在交互式会话中,你经常会同时使用它们两个。如果你打印一个对象,那么它的__str__方法将被调用,而如果你只是单独使用一个对象,那么它的__repr__将被显示:

>>> from decimal import Decimal
>>> a = Decimal(1.25)
>>> print(a)
1.25                  <---- this is from __str__
>>> a
Decimal('1.25')       <---- this is from __repr__

__str__的目的是尽可能地易于人阅读,而__repr__则应该旨在创建一个可用于重新创建对象的字符串,尽管通常不会完全与创建它的方式相同,就像这个例子一样。

对于内置类型来说,__str____repr__返回相同的值也很常见。


1
谢谢提供这个例子,让我更好地理解了默认情况下它的使用方式。 - JayRizzo

18

在之前的答案基础上继续解释,并提供更多示例。如果使用得当,strrepr之间的区别是明确的。简而言之,repr应该返回一个可以复制粘贴以重建对象精确状态的字符串,而str适用于日志记录观察调试结果。下面是一些示例,以查看一些已知库的不同输出。

Datetime

print repr(datetime.now())    #datetime.datetime(2017, 12, 12, 18, 49, 27, 134411)
print str(datetime.now())     #2017-12-12 18:49:27.134452

str适合打印到日志文件中,而repr则适合重新编写为可直接运行的代码或将其转储为命令到一个文件中。

x = datetime.datetime(2017, 12, 12, 18, 49, 27, 134411)

Numpy

print repr(np.array([1,2,3,4,5])) #array([1, 2, 3, 4, 5])
print str(np.array([1,2,3,4,5]))  #[1 2 3 4 5]

在Numpy中,repr再次可以直接使用。

自定义Vector3示例

class Vector3(object):
    def __init__(self, args):
        self.x = args[0]
        self.y = args[1]
        self.z = args[2]

    def __str__(self):
        return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)

    def __repr__(self):
        return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)

在此示例中,repr 再次返回一个可以直接使用/执行的字符串,而 str 则更适用于调试输出。

v = Vector3([1,2,3])
print str(v)     #x: 1, y: 2, z: 3
print repr(v)    #Vector3([1,2,3])

需要记住的一件事是,如果str没有定义但repr有定义,str将自动调用repr。因此,至少定义repr总是个好习惯。


17

当你不确定时,草hopper,去山上阅读古籍。你会在那里发现 __repr__() 应该:

尽可能地看起来像一个有效的Python表达式,可以用它来重新创建一个具有相同值的对象。


7
-1这个答案没有尝试回答实际问题,即使用情况是什么。 - Scott Griffiths
4
@Scott:你是正确的。但是再一次,这个“实际问题”根本没有尝试首先查看主要文档。提出一个问题表明你已经尝试回答它自己,但对其某些方面仍然感到困惑,这是一件事情;而发帖子就像这样是完全另外一回事了。仅仅将他的主题作为一个新问题输入,就显示出前6个建议的SO线程中有5个已经回答了他的问题,但他却无动于衷。我并没有给他一个lmgtfy的回答,但我确实很想这么做。 - Peter Rowell
1
实际上,他确实说过他读过关于__repr__的内容,官方文档并没有真正回答为什么要使用它的问题,而且仅仅因为一个问题在其他地方得到了回答,并不是不在SO上回答的好理由(通常情况下,谷歌搜索会把你带回这里!)如果你认为这个问题不值得回答,那么你可以选择不回答,尽管在这种情况下,我同意它已经在SO上很好地解决了,因此链接到重复的问题将是一个合适的回应。 - Scott Griffiths
实际上,你是错误的。文档明确说明了为什么要使用它,即:“这通常用于调试,因此表示法具有信息丰富和无歧义性非常重要。”我见过太多的论坛(或者说是“论坛”?)因为帮助吸血鬼而沉没,看到它开始在SO上发生,我感到痛心。至于链接到其他明显的SO答案,那就是建议机制的整个目的,当您在输入主题行时,建议机制就会启动,但他选择忽略所有建议。QED和PDQ也是如此。 - Peter Rowell
6
文档仍然没有说明如何使用它进行调试,但我真的不想就此争论。至少我们都同意你的回答没有回答问题,所以我觉得我的负一分还是有道理的。如果一个问题写得很差/重复/琐碎,那么你可以帮助改进这个问题,链接到重复的问题,或者简单地给问题投反对票。我认为我主要的反对意见是:回答应该尝试回答问题 - 有其他机制来批评问题。我现在闭嘴了,因为我觉得我们两个在这里有更好的事情要做。 - Scott Griffiths

7

让我们创建一个没有 __str__ 函数的类。

class Employee:

    def __init__(self, first, last, pay):
        self.first = first 
        self.last = last
        self.pay = pay

emp1 = Employee('Ivan', 'Smith', 90000)

print(emp1)

当我们打印类的实例emp1时,会得到以下结果:
<__main__.Employee object at 0x7ff6fc0a0e48>

这并不是很有帮助,如果我们要用它来显示(比如在html中),这显然不是我们想要打印的内容。

现在,同样的类,但加上了__str__函数:

class Employee:

    def __init__(self, first, last, pay):
        self.first = first 
        self.last = last
        self.pay = pay

    def __str__(self):
        return(f"The employee {self.first} {self.last} earns {self.pay}.")
        # you can edit this and use any attributes of the class

emp2 = Employee('John', 'Williams', 90000)

print(emp2)

现在,我们不再打印出“存在一个对象”,而是得到了我们用__str__函数指定的返回值:

员工 John Williams 的工资为 90000


3

str会以非正式且易于阅读的格式呈现,而repr则提供官方的对象表示。

class Complex:
    # Constructor
    def __init__(self, real, imag):
        self.real = real
        self.imag = imag

    # "official" string representation of an object
    def __repr__(self):
        return 'Rational(%s, %s)' % (self.real, self.imag)

    # "informal" string representation of an object (readable)
    def __str__(self):
        return '%s + i%s' % (self.real, self.imag)

    t = Complex(10, 20)

    print (t)     # this is usual way we print the object
    print (str(t))  # this is str representation of object 
    print (repr(t))  # this is repr representation of object   

Answers : 

Rational(10, 20) # usual representation
10 + i20      # str representation
Rational(10, 20)  # repr representation

1

strrepr 都是表示方式。当您编写类时,可以使用它们。

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __repr__(self):
    return "{}/{}".format(self.n, self.d)

例如,当我打印它的一个实例时,它会返回一些东西。
print(Fraction(1, 2))

导致
1/2

while

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __str__(self):
    return "{}/{}".format(self.n, self.d)
print(Fraction(1, 2))

也会导致
1/2

但是如果你都写了,Python会使用哪一个?

class Fraction:
def __init__(self, n, d):
    self.n = n
    self.d = d
def __str__(self):
    return "str"
def __repr__(self):
    return "repr"

print(Fraction(None, None))

这将导致
str

Python实际上使用str方法而不是repr方法,当两者同时被写入时。


我认为没有理由有两种方法返回(几乎)相同的信息。在我看来,repr字符串最好是“Fraction(n, d)”。请查看官方文档以获取repr方法的更多信息。 - Yaroslav Nikitenko

0
假设您有一个类并希望检查实例,您会发现打印输出并没有提供太多有用的信息。
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age


p1 = Person("John", 36)
print(p1)  # <__main__.Animal object at 0x7f9060250410>

现在看一个带有 str 的类,它显示实例信息,使用 repr 甚至不需要打印。很好,不是吗?
class Animal:
    def __init__(self, color, age, breed):
        self.color = color
        self.age = age
        self.breed = breed

    def __str__(self):
        return f"{self.color} {self.breed} of age {self.age}"

    def __repr__(self):
        return f"repr : {self.color} {self.breed} of age {self.age}"


a1 = Animal("Red", 36, "Dog")
a1  # repr : Red Dog of age 36
print(a1)  # Red Dog of age 36

这是一个错误的repr示例。正确(合理)的字符串应该是'Animal(“Red”,36,“Dog”)'。它允许重新构建对象。“repr:”对打印的字符串表示没有任何价值。只是一个任意无用的常数,抱歉。 - Yaroslav Nikitenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接