__str__和__repr__有什么区别?

3667
28个回答

15

来自 effbot 的 (非官方)Python 参考 Wiki(存档副本)

__str__ "计算对象的“非正式”字符串表示。这与 __repr__ 不同,因为它不必是一个有效的 Python 表达式:相反,可能会使用更方便或更简洁的表示方法。"


4
__repr__ 并不要求返回一个有效的 Python 表达式。 - Mad Physicist

14

说实话,eval(repr(obj))从来没有被使用过。如果你发现自己在使用它,那么应该停止,因为eval是危险的,而字符串是序列化对象的一种非常低效的方式(应该使用pickle代替)。

因此,我建议将__repr__ = __str__。原因是str(list)调用元素的repr(我认为这是Python的最大设计缺陷之一,Python 3没有解决)。实际的repr可能不会对print([your, objects])的输出有太多帮助。

要澄清这一点,根据我的经验,repr函数最有用的用例是将一个字符串放入另一个字符串中(使用字符串格式化)。这样,你就不必担心引号转义或任何其他问题了。但请注意,这里没有发生eval


26
我认为这样做没有抓住重点。使用eval(repr(obj))是一种测试和经验法则 - 如果它能够正确地重新创建原始对象,那么你就拥有了一个不错的__repr__实现。这并不意味着你应该真的用这种方式序列化对象。 - jwg
10
“eval”本身并不危险,不比“unlink”,“open”或写入文件更危险。我们应该停止写入文件吗?因为也许恶意攻击者可以使用任意文件路径将内容放置在其中?如果被愚蠢的人愚蠢地使用,一切都是危险的。愚蠢是危险的。Dunning-Kruger效应是危险的。“eval”只是一个函数。 - Luis Masuelli

12

str - 从给定对象创建新的字符串对象。

repr - 返回对象的规范字符串表示形式。

区别:

str():

  • 使对象可读
  • 为最终用户生成输出

repr():

  • 需要能够重现对象的代码
  • 为开发人员生成输出

10
你可以从这段代码中获得一些见解。
class Foo:
    def __repr__(self):
        return "repr"

    def __str__(self):
        return "str"

foo = Foo()
foo  # repr
print(foo)  # str

9

__str__方法可以通过调用str(obj)在对象上调用,并应返回一个易于理解的字符串。

__repr__方法可以通过调用repr(obj)在对象上调用,并应返回内部对象(对象字段/属性)

以下示例可能有所帮助:

class C1:pass

class C2:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

class C3:        
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")

class C4:        
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")
    def __repr__(self):        
         return str(f"{self.__class__.__name__} class repr")


ci1 = C1()    
ci2 = C2()  
ci3 = C3()  
ci4 = C4()

print(ci1)       #<__main__.C1 object at 0x0000024C44A80C18>
print(str(ci1))  #<__main__.C1 object at 0x0000024C44A80C18>
print(repr(ci1)) #<__main__.C1 object at 0x0000024C44A80C18>
print(ci2)       #C2 class str
print(str(ci2))  #C2 class str
print(repr(ci2)) #<__main__.C2 object at 0x0000024C44AE12E8>
print(ci3)       #C3 class repr
print(str(ci3))  #C3 class repr
print(repr(ci3)) #C3 class repr
print(ci4)       #C4 class str 
print(str(ci4))  #C4 class str 
print(repr(ci4)) #C4 class repr

9

其他答案中缺少的一个方面是,通常模式为:

  • __str__ 的目标:可读性强
  • __repr__ 的目标:无歧义,可能通过 eval 机器可读

不幸的是,这种区分是有缺陷的,因为 Python REPL 和 IPython 在 REPL 控制台中打印对象时使用 __repr__(请参见相关问题 PythonIPython)。因此,针对交互式控制台工作(例如 Numpy 或 Pandas)的项目已经开始忽略上述规则,并提供了一个易于人阅读的 __repr__ 实现。


9

来自书籍《流畅的Python》:

一个Python对象的基本要求是提供可用的字符串表示形式,一种用于调试和日志记录,另一种用于呈现给最终用户。这就是为什么数据模型中存在特殊方法 __repr____str__


6
优秀的答案已经涵盖了__str__和__repr__之间的区别,对我来说,前者可被最终用户读取,后者对开发人员尽可能有用。鉴于此,我发现__repr__的默认实现通常无法实现这个目标,因为它省略了对开发人员有用的信息。
出于这个原因,如果我的__str__足够简单,我通常会尝试通过以下方式兼顾两者的优点:
def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))

6
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')

当调用 decimal.Decimal(23) / decimal.Decimal("1.05") 的结果进行 print() 时,会输出原始数字;这个输出是以字符串形式呈现的,可以通过 __str__() 实现。如果我们只输入表达式,将得到一个 decimal.Decimal 输出 — 这个输出是以表示形式呈现的,可以通过 __repr__() 实现。所有 Python 对象都有两种输出形式。字符串形式旨在为人类可读。表示形式旨在产生输出,如果将其馈送给 Python 解释器,则(可能时)会重现所表示的对象。

5
一个重要的事情需要记住,即容器的__str__使用包含对象的__repr__
>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"
< p > Python更注重无歧义性而非易读性,一个tuple__str__调用会调用包含对象的__repr__,即对象的"正式"表示。虽然正式表示比非正式表示更难读,但它是无歧义的并且更能防止错误。


__str__ 没有被定义时,它使用 __repr__!所以,你是错误的。 - jiten

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