__str__和__repr__之间的区别?

时间:2009-09-17 04:27:46

标签: python magic-methods repr

Python中__str____repr__之间有什么区别?

23 个答案:

答案 0 :(得分:2450)

Alex总结得很好,但令人惊讶的是,它太简洁了。

首先,让我重申Alex’s post中的要点:

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

默认实施无用

这主要是一个惊喜,因为Python的默认值往往非常有用。但是,在这种情况下,__repr__的默认值将起作用:

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

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

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

__repr__的目标是明确的

让我直接说出来 - 我不相信调试器。我真的不知道如何使用任何调试器,并且从未认真使用过。此外,我认为调试器的大错是它们的基本性质 - 我调试的大多数失败发生在很久很久以前,在一个遥远的星系中。这意味着我确实相信,在宗教热情的情况下,伐木。记录是任何体面的即发即弃服务器系统的生命线。 Python可以很容易地记录:可能有一些项目特定的包装器,你需要的只是一个

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的所有信息。如果这很容易,至少以模糊的方式,做到这一点。如果没有,请确保您有足够的c信息。我通常使用类似eval的格式:"MyClass(this=%r,that=%r)" % (self.this,self.that)。这并不意味着你可以实际构造MyClass,或者那些是正确的构造函数参数 - 但它是一种有用的形式来表达“这是你需要了解的关于这个实例的一切”。

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

__str__的目标是可读

具体而言,它无意明确 - 请注意str(3)==str("3")。同样,如果你实现了一个IP抽象,它的str看起来像192.168.1.1就好了。在实现日期/时间抽象时,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]

是?不是特别的。具体来说,容器中的字符串会发现太容易打扰它的字符串表示。面对模棱两可,请记住,Python抵制猜测的诱惑。如果您在打印列表时需要上述行为,只需

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

(你也可以弄清楚如何处理字典。

<强>摘要

为您实施的任何类实施__repr__。这应该是第二天性。如果您认为字符串版本在可读性方面存在错误,那么实现__str__

答案 1 :(得分:444)

我的经验法则:__repr__适用于开发人员,__str__适用于客户。

答案 2 :(得分:359)

除非您特别采取行动以确保其他方式,否则大多数课程都没有有用的结果:

>>> 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__,而不是__str__。而且,尽管在典型的文档中找到了关于该主题的文字,但几乎没有人会让__repr__个对象成为eval可能用来构建一个平等对象的字符串(它太难了,而且不知道如何实际导入相关模块使其实际上变得不可能。)

所以,我的建议是:专注于让__str__合理地让人类可读,__repr__尽可能明确无误,即使这会干扰制作__repr__的模糊无法实现的目标可以接受的返回值作为__eval__的输入!

答案 3 :(得分:154)

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

__str__ :您认为该文本形式的对象是什么

e.g。

>>> 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

答案 4 :(得分:131)

  

简而言之,__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:

  

repr(object)

     

返回包含对象的可打印表示的字符串。这与转换产生的值相同(反向   引号)。能够以此方式访问此操作有时很有用   一个普通的功能。对于许多类型,此功能尝试   返回一个字符串,该字符串将产生具有相同值的对象   传递给eval(),否则表示是一个包含在其中的字符串   包含对象类型名称的尖括号   以及通常包括名称和名称的其他信息   对象的地址。类可以控制此函数返回的内容   通过定义__repr__()方法为其实例。

以下是str:

的文档
  

str(object='')

     

返回包含可打印的字符串   对象的表示。对于字符串,这将返回字符串   本身。与repr(object)的区别在于str(object)没有   总是尝试返回eval()可接受的字符串;它的   目标是返回可打印的字符串。如果没有给出参数,则返回   空字符串''

答案 5 :(得分:96)

  

Python中__str____repr__之间的区别是什么?

__str__(读作“dunder(双下划线)字符串”)和__repr__(读作“dunder-repper”(表示“)”)都是返回字符串的特殊方法关于对象的状态。

如果缺少__repr__

__str__会提供备份行为。

因此,首先应该编写一个__repr__,允许您从它返回的字符串中重新实例化等效对象,例如使用eval或在Python shell中使用character-for-character键入它。

以后的任何时候,当人们认为有必要时,可以为实例的用户可读字符串表示写一个__str__

__str__

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

__repr__

__repr__方法由内置函数repr调用,并在评估返回对象的表达式时在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.

也就是说,对于大多数对象,如果键入repr打印的内容,则应该能够创建等效对象。 但这不是默认实现。

__repr__

的默认实施

默认对象__repr__是(C Python source)类似于:

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

这意味着默认情况下,您将打印对象所在的模块,类名以及其在内存中的位置的十六进制表示形式 - 例如:

<__main__.Foo object at 0x7f80665abdd0>

这些信息不是很有用,但没有办法得出如何准确地创建任何给定实例的规范表示,并且它总比没有好,至少告诉我们如何在内存中唯一地识别它。 / p>

__repr__如何有用?

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

import datetime

如果我们在shell中调用datetime.now,我们将看到重新创建等效日期时间对象所需的一切。这是由日期时间__repr__

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

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

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

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

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

我如何实施它们?

在开发过程中,如果可能的话,您将希望能够以相同的状态再现对象。例如,这是datetime对象定义__repr__Python source)的方式。由于重现这样一个对象所需的所有属性,它相当复杂:

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 source)如何实现__str__,它很容易做到,因为它已经有一个以ISO格式显示它的函数:

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

设置__repr__ = __str__

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

设置__repr__ = __str__很愚蠢 - __repr____str__的后备,而__repr__是为开发人员在调试中使用而编写的,应该在编写{{__str__之前编写1}}。

只有当您需要对象的文本表示时,才需要__str__

结论

为您编写的对象定义__repr__,以便您和其他开发人员在开发时使用它时具有可重现的示例。当需要人类可读的字符串表示时,定义__str__

答案 6 :(得分:24)

除了给出的所有答案外,我想补充几点: -

1)只需在交互式python控制台上编写对象名称并按Enter即可调用__repr__()

2)使用带有print语句的对象时调用__str__()

3)如果缺少__str__,则打印并使用str()的任何函数调用对象的__repr__()

4)__str__()个容器在被调用时将执行其包含元素的__repr__()方法。

5)在str()内调用的__str__()可能会在没有基本情况的情况下递归,并且最大递归深度会出错。

6)__repr__()可以调用repr(),它会尝试自动避免无限递归,用...替换已经表示的对象。

答案 7 :(得分:17)

Hans Petter Langtangen所着的 Python脚本计算科学 一书的第358页,它明确指出

  • __repr__的目标是对象的完整字符串表示;
  • __str__将返回一个很好的字符串进行打印。

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

  • repr =重现
  • str =字符串(代表)

从用户的角度来看 虽然这是我在学习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'

答案 8 :(得分:11)

老实说,eval(repr(obj))从未被使用过。如果你发现自己正在使用它,你应该停下来,因为eval是危险的,并且字符串是一种非常低效的序列化对象的方法(改为使用pickle)。

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

为了限定这一点,根据我的经验,repr函数最有用的用例是将一个字符串放在另一个字符串中(使用字符串格式)。这样,您不必担心转义引号或任何内容。但请注意,此处没有eval发生。

答案 9 :(得分:11)

简单地说:

__str__用于显示对象的字符串表示,以便其他人轻松阅读

__repr__用于显示 对象的字符串表示。

我想说我想创建一个Fraction类,其中分数的字符串表示是&#39;(1/2)&#39;并且对象(分数类)将表示为&#39;分数(1,2)&#39;

所以我们可以创建一个简单的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)

答案 10 :(得分:10)

来自an (An Unofficial) Python Reference Wiki (archive copy)的effbot:

__str__计算对象的”非正式“字符串表示。这与__repr__的不同之处在于它不必是有效的Python表达式:更方便或简洁的表示可以改为使用。

答案 11 :(得分:7)

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

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

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

答案 12 :(得分:4)

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

出于这个原因,如果我有一个足够简单的__str__,我通常会尝试用这样的方法来充分利用这两个世界:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))

答案 13 :(得分:4)

Fluent Python 一书

  

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

答案 14 :(得分:3)

  

要记住的一件重要事情是容器__str__使用包含的对象&#39; __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倾向于明确可读性__str__调用tuple调用包含的对象&#39; __repr__,对象的&#34; formal&#34; 表示。虽然正式表示比非正式表达更难阅读,但它对于错误是明确的和更强大的。

答案 15 :(得分:3)

简而言之:

class Demo:
  def __repr__(self):
    return 'repr'
  def __str__(self):
    return 'str'

demo = Demo()
print(demo) # use __str__, output 'str' to stdout

s = str(demo) # __str__ is used, return 'str'
r = repr(demo) # __repr__ is used, return 'repr'

import logging
logger = logging.getLogger(logging.INFO)
logger.info(demo) # use __str__, output 'str' to stdout

from pprint import pprint, pformat
pprint(demo) # use __repr__, output 'repr' to stdout
result = pformat(demo) # use __repr__, result is string which value is 'str'

答案 16 :(得分:3)

问:__str__()__repr__()有什么区别?

TL; DR: Differences between str()/repr() and __str__()/__repr__()

这个问题已经存在了很长时间,并且有各种各样的答案,其中大多数是正确的(更不用说一些Python社区传奇[!]了)。但是,当涉及到细节时,这个问题类似于要求内置函数str()repr()之间的区别。我将用自己的语言来描述差异(这意味着我可能会从Core Python Programming中“自由地”借钱,所以请原谅我。)

两者 str()repr()具有相同的基本工作:它们的目标是返回Python对象的字符串表示形式。字符串表示形式的种类是它们的区别所在。

  • str()__str()__返回以下内容的 printable 字符串表示形式 对象...人类可读/供人类消费的东西
  • repr()__repr()__返回对象的字符串表示形式,该对象是 有效的Python对象,您可以将其传递给eval()或在Python shell中键入内容而不会出错。

例如,让我们为x分配一个字符串,为int分配一个y

>>> x, y = 'foo', 123
>>> str(x), str(y)
('foo', '123')

我们可以将引号内的内容逐字输入到Python解释器中吗?

>>> 123
123
>>> foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined

很明显,您可以使用int,但不一定需要使用str。尽管我可以将'123'传递给eval(),但不适用于'foo'

>>> eval('123')
123
>>> eval('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'foo' is not defined

现在让我们尝试repr();再次,转储每个字符串的双引号中的内容:

>>> repr(x), repr(y)
("'foo'", '123')
>>> 123
123
>>> 'foo'
'foo'

哇,他们都都在工作吗?这是因为'foo'是该字符串的可打印字符串表示形式,但不可可评估,而"'foo'"是可评估的。 123是由intstr()调用的有效Python repr()。当我们用这些调用eval()时会发生什么?

>>> eval('123')
123
>>> eval("'foo'")
'foo'

之所以有效,是因为123'foo'是有效的Python对象。另一个要点是,尽管有时两者都返回相同的内容(相同的字符串表示形式),但情况并非总是如此。 (是的,是的,我可以在foo工作的地方创建一个变量eval(),但这不是重点。)

有关这两对的更多类事实

  1. 有时,str()repr()被隐式调用 ,这意味着它们是在用户执行时被调用的:用户执行 print (Py1 / Py2)或调用print()(Py3 +),即使用户未明确调用str(),也要在显示对象之前代表他们进行调用。
  2. 在Python Shell(交互式解释器)中,如果在>>>提示符下输入变量并按RETURN,则解释器将显示在该对象上隐式调用的repr()的结果。
  3. 要将str()repr()连接到__str__()__repr__(),请意识到对内置函数即str(x)或{{1 }}会导致调用其对象的相应特殊方法:repr(y)x.__str__()
  4. 通过为您的 Python类实现y.__repr()____str__(),您可以重载内置函数(__repr__()str()),从而允许类的实例要传递到repr()str()中。进行此类调用后,他们会转过身来并调用类的repr()__str__()(按#3)。

答案 17 :(得分:2)

直观地了解__str____repr__并永久地区分它们。

__str__返回给定对象的字符串伪装体,以便眼睛可读 __repr__返回给定对象的真实肉体(返回自身),以便明确识别。

在示例中查看

In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form

关于__repr__

In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.

我们可以方便地对__repr__结果进行算术运算。

In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
    ...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)

如果在__str__

上应用操作
In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'

只返回错误。

另一个例子。

In [36]: str('string_body')
Out[36]: 'string_body' # in string form

In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside

希望这有助于您建立具体理由来探索更多答案。

答案 18 :(得分:1)

__repr__在任何地方都使用,除了printstr方法(定义{{​​1}}时!)

答案 19 :(得分:0)

  1. __str__必须返回字符串对象,而__repr__可以返回任何python表达式。
  2. 如果缺少__str__实现,则将__repr__函数用作后备。如果缺少__repr__函数的实现,则没有回退。
  3. 如果__repr__函数返回对象的字符串表示形式,则可以跳过__str__函数的实现。

来源:https://www.journaldev.com/22460/python-str-repr-functions

答案 20 :(得分:0)

可以通过调用__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

答案 21 :(得分:0)

每个对象都从所有对象创建的基类继承__repr__

class Person:
     pass

p=Person()

如果您致电repr(p),则默认情况下:

 <__main__.Person object at 0x7fb2604f03a0>

但是,如果您呼叫str(p),则会得到相同的输出。这是因为当__str__不存在时,Python会调用__repr__

让我们实现自己的__str__

class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __repr__(self):
        print("__repr__ called")
        return f"Person(name='{self.name}',age={self.age})"

p=Person("ali",20)

print(p)str(p)将返回

 __repr__ called
     Person(name='ali',age=20)

让我们添加__str__()

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __repr__(self):
        print('__repr__ called')
        return f"Person(name='{self.name}, age=self.age')"
    
    def __str__(self):
        print('__str__ called')
        return self.name

p=Person("ali",20)

如果我们调用print(p)和str(p),它将调用__str__()以便返回

__str__ called
ali

repr(p)将返回

代表 “人(姓名='ali,age = self.age')”

我们省略__repr__,而只是实现__str__

class Person:
def __init__(self, name, age):
    self.name = name
    self.age = age

def __str__(self):
    print('__str__ called')
    return self.name

p=Person('ali',20)

print(p)将查找__str__并返回:

__str__ called
ali

注意=如果我们定义了__repr____str__,则f'name is {p}'将调用__str__

答案 22 :(得分:0)

您可以从这段代码中获得一些见解:

class Foo():
    def __repr__(self):
        return("repr")
    def __str__(self):
        return("str")

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