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__
如果打印一个对象,或者将其传递给format
, str.format
或str
,那么如果定义了__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__
实现。