提问



__str____str____repr__之间有什么区别?

最佳参考


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


首先,让我重申亚历克斯的帖子中的要点:



  • 默认的实现是没用的(很难想到一个不会的,但是是的)

  • __repr__目标是明确的

  • __str__目标是可读的

  • Container's __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__实现中使用repr() [[或%r格式化字符,或者你正在击败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


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

其它参考2


除非您特别采取行动以确保其他方面,否则大多数课程都不会对以下任何一方产生有用


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


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


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


例如


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



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



  

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源代码),如:[190]


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


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


<__main__.Foo object at 0x7f80665abdd0>


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


__repr__如何有用?



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


import datetime


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


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


如果我们打印一个日期时间对象,我们会看到一个很好的人类可读(实际上是ISO)格式。这是由datetimes __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源代码)。这是相当复杂的,因为重现这样一个对象需要的所有属性:[191]


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__。这里是日期时间对象(Python源代码)如何实现__str__,它很容易做到,因为它已经有一个以ISO格式显示它的函数:[192]


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


设置__repr__ = __str__?



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


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


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


结论



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

其它参考6


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


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


根据我的经验,repr函数最有用的用例是将字符串放在另一个字符串中(使用字符串格式)。这样,你不必担心转义引号或任何东西。但请注意,这里没有eval发生。

其它参考7


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


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


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


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


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


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


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

其它参考8


简而言之:


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


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


假设我想创建一个Fraction类,其中分数的字符串表示为(1/2),对象(分数类)将表示为分数(1,2)


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

其它参考9


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



  • __repr__的目标是对象的完整字符串表示;

  • __str__将返回一个很好的字符串进行打印。



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



  • repr =重现

  • str=string(representation)



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

其它参考10


来自effbot的http://pyref.infogami.com/__str__:[193]


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

其它参考11


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


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


差异:


STR():



  • 使对象可读

  • 为最终用户生成输出



再版():



  • 需要复制对象的代码

  • 为开发人员生成输出


其它参考12


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



  • __str__的目标:人类可读

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


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

其它参考13


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


出于这个原因,如果我有一个足够简单的__str__,我通常只是试图通过以下方式获得两全其美:


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

其它参考14


>>> 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 __()实现。如果我们只是输入表达式,我们得到一个十进制。十进制输出 - 这个输出是表示形式,可以用__repr __()来实现。所有Python对象都有两种输出形式。字符串形式设计为人类可读的。表示形式旨在产生输出,如果输入到Python解释器将(如果可能)重新生成表示的对象

其它参考15



  要记住的一件重要事情是容器__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__,形式表示尽管正式表示比非正式表达更难阅读,但它对于错误是明确的和更强大的。

其它参考16


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


从书中:流利的Python

其它参考17


简而言之:


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'

其它参考18


理解__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


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

其它参考19


更加清晰
来自博客[196]


str 就像toString。创建,以便您可以打印数据
repr 就像序列化或泡菜一样。如果我需要使用eval(),我如何重新创建这个对象


>>> import datetime
>>> now = datetime.datetime.now() 
>>> str(now)
'2015-04-04 20:51:31.766862'
>>> repr(now)
'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)'
>>mydate = eval(repr(now))

其它参考20


除了printstr定义__str__时,__repr__随处可见