Python中__str__和__repr__的区别

Python __str____repr__什么区别?

亚历克斯总结得很好,但是,令人惊讶的是,太简洁了。

首先,让我重申Alex的post中的主要观点:

  • 默认的实现是无用的(很难想象一个不会的,但是是的)
  • __repr__目标是明确的
  • __str__目标是可读的
  • 容器的__str__使用包含的对象' __repr__

默认的实现是没用的

这大多是一个惊喜,因为Python的默认值相当有用。 但是,在这种情况下, __repr__具有默认值,其行为如下:

 return "%s(%r)" % (self.__class__, self.__dict__) 

太危险了(例如,如果对象互相引用,则太容易进入无限recursion)。 所以Python警察出来。 请注意,有一个默认值是true:如果__repr__被定义,并且__str__不是,则该对象的行为就像__str__=__repr__

这就是说,简单地说:几乎每个实现的对象都应该有一个可用于理解对象的函数__repr__ 。 实现__str__是可选的:如果您需要“漂亮的打印”function(例如,由报告生成器使用),请执行此操作。

__repr__的目标是明确的

让我出来说出口 – 我不相信debugging器。 我真的不知道如何使用任何debugging器,从来没有认真对待过。 而且,我相信debugging器中的大错是它们的基本性质 – 我debugging的大多数故障发生在很久很久以前,在一个遥远的星系中。 这意味着我相信,在宗教的热情下,在伐木。 logging是任何像样的“即燃即用”服务器系统的命脉。 Python可以很容易地logging:也许有一些项目特定的包装,你需要的只是一个

 log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c) 

但是你必须做最后一步 – 确保你实现的每一个对象都有一个有用的repr,所以像这样的代码可以工作。 这就是为什么“eval”出现的原因:如果你有足够的信息如此eval(repr(c))==c ,那就意味着你知道所有关于c 。 如果这很容易,至less以模糊的方式,做到这一点。 如果没有,请确保您有足够的有关c信息。 我通常使用类似eval的格式: "MyClass(this=%r,that=%r)" % (self.this,self.that) 。 这并不意味着你可以实际构造MyClass,或者说这些是正确的构造函数参数 – 但它是expression“这是你需要知道的关于这个实例的一切”的一种有用的forms。

注意:我使用了上面的%r ,而不是%s 。 你总是希望在__repr__实现中使用repr() [或%r格式化字符,等价地],或者你正在击败repr的目标。 您希望能够区分MyClass(3)MyClass("3")

__str__的目标是可读的

具体而言,它不是明确的 – 注意str(3)==str("3") 。 同样的,如果你实现了一个IP抽象,那么看起来像192.168.1.1就好了。 当实现date/时间抽象时,str可以是“2010/4/12 15:35:22”等。目标是以用户而不是程序员想要读取它的方式表示。 斩掉无用的数字,假装是其他类 – 只要它支持可读性,这是一个改进。

容器的__str__使用包含的对象' __repr__

这似乎令人惊讶,不是吗? 这是一个小小的,但可读性如何

 [moshe is, 3, hello world, this is a list, oh I don't know, containing just 4 elements] 

是? 不是特别的。 具体而言,容器中的string会发现太容易干扰其string表示。 面对歧义,请记住,Python抵制猜测的诱惑。 如果在打印列表时需要上述行为,

 print "["+", ".join(l)+"]" 

(你也可以找出如何处理字典。

概要

为您实现的任何类实现__repr__ 。 这应该是第二性质的。 实现__str__如果你认为有一个string版本更易于阅读,而偏向于更多的含糊不清。

我的经验法则: __repr__是为开发人员, __str__是为客户。

除非您专门采取措施来确保否则,否则大多数class级对下列任何一项都没有帮助:

 >>> class Sic(object): pass ... >>> print str(Sic()) <__main__.Sic object at 0x8b7d0> >>> print repr(Sic()) <__main__.Sic object at 0x8b7d0> >>> 

正如你所看到的 – 没有什么区别,除了类和对象的id之外没有任何信息。 如果你只是重写其中的一个…:

 >>> class Sic(object): ... def __repr__(object): return 'foo' ... >>> print str(Sic()) foo >>> print repr(Sic()) foo >>> class Sic(object): ... def __str__(object): return 'foo' ... >>> print str(Sic()) foo >>> print repr(Sic()) <__main__.Sic object at 0x2617f0> >>> 

如你所见,如果你覆盖__repr__ ,这也是用于__str__ ,但反之亦然。

其他重要的小__str__要知道:内置容器上的__repr__使用__repr__ ,而不是__str__ ,它包含的项目。 而且,尽pipe在典型文档中发现了关于这个主题的文字,但是几乎没有人__repr__使得对象的__repr__变成一个string, eval可能会使用这个string来构build一个平等的对象(这太难了,而且不知道相关模块是如何导入的它实际上是不可能的)。

所以,我的build议是: __str__使__str__合理的可读, __repr__明确无误,尽pipe这会干扰使__repr__的返回值作为__eval__input可接受的模糊不__repr__目标!

__repr__ :python对象的表示通常eval会将其转换回该对象

__str__ :是你认为是文本forms的对象

例如

 >>> s="""w'o"w""" >>> repr(s) '\'w\\\'o"w\'' >>> str(s) 'w\'o"w' >>> eval(str(s))==s Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1 w'o"w ^ SyntaxError: EOL while scanning single-quoted string >>> eval(repr(s))==s True 

总之, __repr__的目标是明确的, __str__是可读的。

这是一个很好的例子:

 >>> import datetime >>> today = datetime.datetime.now() >>> str(today) '2012-03-14 09:21:58.130922' >>> repr(today) 'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)' 

阅读本文档以获取更多信息:

repr(object)

返回包含对象的可打印表示的string。 这与转换(反向引号)产生的价值相同。 能够以普通函数的forms访问这个操作有时很有用。 对于很多types来说,这个函数试图返回一个string,当传递给eval()时会返回一个相同值的对象,否则表示就是一个用尖括号括起来的string,它包含了对象types的名字附加信息通常包括对象的名称和地址。 一个类可以通过定义一个__repr__()方法来控制这个函数为其实例返回的__repr__()

这是str的文档:

str(object='')

返回一个包含对象的可打印表示的string。 对于string,这将返回string本身。 与repr(object)的区别在于str(object)并不总是试图返回eval()所接受的string。 其目标是返回一个可打印的string。 如果没有给出参数,则返回空string''

Python中的__str____repr__什么区别?

__str__ (读作“dunder(double-underscore)string”)和__repr__ (读作“dunder-repper”(用于“表示”))都是根据对象的状态返回string的特殊方法。

如果__str__缺失, __repr__提供备份行为。

所以我们应该首先编写一个__repr__ ,它允许你从它返回的string中重新实例化一个等价的对象,比如使用eval或者在Python shell中用字符__repr__字符。

在以后的任何时候,如果有人认为这是必要的,那么可以为用户可读的string表示写一个__str__

__str__

如果打印一个对象,或者将其传递给formatstr.formatstr ,那么如果定义了__str__方法,那么将调用该方法,否则将使用__repr__

__repr__

__repr__方法由内置函数repr调用,当它计算一个返回对象的expression式时,它将在你的python shell中被回显。

由于它为__str__提供了一个备份,如果你只能写一个备份,可以从__repr__

这里是内置的repr帮助:

 repr(...) repr(object) -> string Return the canonical string representation of the object. For most object types, eval(repr(object)) == object. 

也就是说,对于大多数对象,如果inputrepr打印的内容,应该可以创build一个等效的对象。 但是这不是默认的实现。

__repr__默认实现

默认对象__repr__是( C Python源代码 ),类似于:

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

这意味着默认情况下,您将打印对象所来自的模块,类名称以及其在内存中的位置的hex表示,例如:

 <__main__.Foo object at 0x7f80665abdd0> 

这个信息并不是很有用,但是没有办法推导出如何准确地创build任何给定实例的规范表示,总比什么都没有好,至less告诉我们如何在内存中唯一地识别它。

__repr__如何有用?

让我们看看它是多么有用,使用Python shell和datetime对象。 首先,我们需要导入datetime模块:

 import datetime 

如果我们在shell中调用datetime.now ,我们将看到我们需要重新创build一个等效的date时间对象的一切。 这是由datetime __repr__创build的:

 >>> datetime.datetime.now() datetime.datetime(2015, 1, 24, 20, 5, 36, 491180) 

如果我们打印一个date时间对象,我们看到一个很好的人类可读(实际上,ISO)格式。 这是由datetime的__str__实现的:

 >>> print(datetime.datetime.now()) 2015-01-24 20:05:44.977951 

重新创build我们丢失的对象是一件简单的事情,因为我们没有通过从__repr__输出中复制和粘贴将其分配给一个variables,然后将其打印出来,并将其与另一个对象放在同一个人类可读输出中:

 >>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180) >>> print(the_past) 2015-01-24 20:05:36.491180 

我如何执行它们?

在开发过程中,如果可能的话,您将希望能够以相同的状态再现对象。 例如,这是datetime对象如何定义__repr__ ( Python源代码 )。 这是相当复杂的,因为所有需要重现这样一个对象的属性:

 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 = ", ".join(map(str, L)) s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s) if self._tzinfo is not None: assert s[-1:] == ")" s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" return s 

如果你想让你的对象有更多的人类可读表示,你可以实现__str__接下来。 下面是datetime对象( Python源代码 )如何实现__str__ ,这很容易实现,因为它已经有了一个以ISO格式显示的函数:

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

设置__repr__ = __str__

这是对另一个答案的批评,build议设置__repr__ = __str__

设置__repr__ = __str__是愚蠢的 – __repr____str____repr__的后备,为开发人员在debugging时使用而编写,应该在写入__str__之前写入。

只有在需要对象的文本表示时才需要__str__

结论

为您编写的对象定义__repr__ ,这样您和其他开发人员在开发过程中使用它时就具有可重复的示例。 当你需要一个可读的string表示的时候定义__str__

eval(repr(obj))eval(repr(obj))从来没有被使用过。 如果你发现自己使用它,你应该停止,因为eval是危险的,string是一个非常低效的方式来序列化你的对象(而不是使用pickle )。

所以我build议设置__repr__ = __str__ 。 原因是str(list)在元素上调用repr (我认为这是Python 3最大的devise缺陷之一,而Python 3没有解决这个问题)。 一个实际的repr可能不会很有帮助,因为print [your, objects]的输出。

根据我的经验,为了限定这一点, repr函数最有用的用例是将一个string放在另一个string中(使用string格式)。 这样,你不必担心逃脱报价或任何东西。 但请注意,这里没有eval发生。

来自http://pyref.infogami.com/__str__ by effbot:

__str__ “计算对象的”非正式“string表示forms,这与__repr__不同之处在于,它不一定是有效的Pythonexpression式:可以使用更简便或更简洁的表示forms。

简单地说:

__str__用于显示对象的string表示, 以便其他人轻松读取

__repr__用于显示对象的string表示forms。

假设我想要创build一个Fraction类,其中一个Fraction的string表示forms为“(1/2)”,而对象(分数类)将表示为“分数(1,2)”

所以我们可以创build一个简单的Fraction类:

 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)当你用print语句使用object时, __str__()被调用。 如果__str__缺失,则打印调用__repr__()对象。

2)当您在交互式python控制台上简单地写对象的名字并按回车时, __repr__()被调用。

3)容器的__str__() ,被调用的时候会执行其包含的元素的__repr__()方法。

在Hans Petter Langtangen的计算科学Python脚本的第358页中,它明确指出这一点

  • repr的目标是对象的完整string表示;
  • str是返回一个很好的string打印。

所以,我更喜欢把它们理解为

  • repr =重现
  • str = string(表示)

从用户的angular度来看,虽然这是我学习Python时犯的一个误解。

在同一页面上也给出了一个小但很好的例子,如下所示:

 In [38]: str('s') Out[38]: 's' In [39]: repr('s') Out[39]: "'s'" In [40]: eval(str('s')) Traceback (most recent call last): File "<ipython-input-40-abd46c0c43e7>", line 1, in <module> eval(str('s')) File "<string>", line 1, in <module> NameError: name 's' is not defined In [41]: eval(repr('s')) Out[41]: 's' 

str – 从给定对象创build一个新的string对象。

repr – 返回对象的规范string表示forms。

区别:

STR():

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

再版():

  • 需要重现对象的代码
  • 为开发者生成输出
 >>> print(decimal.Decimal(23) / decimal.Decimal("1.05")) 21.90476190476190476190476190 >>> decimal.Decimal(23) / decimal.Decimal("1.05") Decimal('21.90476190476190476190476190') 

当print()对decimal.Decimal(23)/ deci- mal.Decimal(“1.05”)的结果被调用时,原始数字被打印; 这个输出是用__str __()来实现的stringforms 。 如果我们简单地inputexpression式,我们得到一个十进制。小数输出 – 这个输出是以__repr __()可以实现的表示forms 。 所有的Python对象都有两种输出forms。 stringforms被devise为人类可读的。 具有代表性的forms被devise为产生输出,如果input到Python解释器将(可能的话)重新生成所表示的对象

一个重要的事情要记住的是,容器的__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))" 

Python倾向于可读性的明确性tuple__str__调用调用了包含对象的__repr__ ,即对象的“forms”表示。 尽pipe正式的表述比非正式的更难以阅读,但它对于错误是毫不含糊和更强大的。

优秀的答案已经涵盖了__str____repr__之间的区别,对我来说,前者甚至可以被最终用户读取,而后者对开发人员来说是有用的。 鉴于此,我发现__repr__的默认实现常常无法实现此目标,因为它省略了对开发人员有用的信息。

出于这个原因,如果我有一个简单的__str__ ,我通常只是试图用这样的东西来获得两全其美的__str__

 def __repr__(self): return '{0} ({1})'.format(object.__repr__(self), str(self)) 
 "A basic requirement for a Python object is to provide usable string representations of itself, one used for debugging and logging, another for presentation to end users. That is why the special methods __repr__ and __str__ exist in the data model." 

从这本书:stream利的Python

其他答案中缺less一个方面。 一般来说,模式是这样的:

  • __str__目标:人类可读
  • __repr__目标:明确的,可能通过eval机器可读

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