有什么区别 __str____repr__ 在Python中?

有帮助吗?

解决方案

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

首先我要重申一下要点 亚历克斯的帖子:

  • 默认实现是无用的(很难想象一个没有用的实现,但是是的)
  • __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__ 如果您认为拥有一个在可读性方面存在错误的字符串版本会很有用。

其他提示

我的经验法则: __ repr __ 适用于开发人员, __ str __ 适用于客户。

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

>>> 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 __ 的输入接受!

__ 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
  

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

  

<代码>再版(对象)

     

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

以下是str:

的文档
  

<代码> STR(对象= '')

     

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

  

Python中的 __ str __ __ repr __ 有什么区别?

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

如果缺少 __ str __

__ repr __ 会提供备份行为。

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

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

<代码> __ STR __

如果您打印一个对象,或将其传递给 format str.format str ,那么如果 __ str__定义了方法,将调用该方法,否则将使用 __ 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源代码)类似于:

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 ,我们将看到重新创建等效日期时间对象所需的一切。这是由datetime __ 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源)。由于重现这样一个对象所需的所有属性,它相当复杂:

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

如果您希望对象具有更易于阅读的表示形式,则可以实现 __ str __ 。以下是datetime对象的方式(

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

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

2)使用带有print语句的对象时,会调用 __ str __()

3)如果缺少 __ str __ ,则使用 str()打印和任何函数调用object的 __ repr __()

4)容器的 __ str __(),当被调用时,将执行其包含元素的 __ repr __()方法。

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

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

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

  • __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'

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

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

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

简单地说:

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

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

假设我要创建一个 Fraction 类,其中分数的字符串表示为'(1/2)',对象(Fraction类)将表示为'Fraction(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)

来自(非官方)Python参考维基(存档副本)由effbot:

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

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

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

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

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

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

差异:

字符串():

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

代表():

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

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

出于这个原因,如果我有一个足够简单的 __ str __ ,我通常只是试着通过以下方式充分利用这两个世界:

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

Fluent Python 一书

  

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

  

要记住的一件重要事情是容器的 __ 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倾向于明确可读性 __ str __ 调用元组调用包含的对象' __ repr __ ,对象的“正式”表示。虽然正式表示比非正式表达更难阅读,但它对于错误是明确的和更强大的。

简而言之:

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'
>>> 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(&quot; 1.05&quot;)的结果上调用 print()时,打印原始数字;此输出采用字符串形式,可以使用 __ str __()来实现。如果我们只是输入表达式,我们得到 decimal.Decimal 输出&#8212;此输出采用表示形式,可以使用 __ repr __()来实现。所有Python对象都有两种输出形式。字符串形式设计为人类可读的。表示形式旨在产生输出,如果输入到Python解释器将(如果可能)再现所表示的对象。

直观地理解 __ 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

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

除了 print str 方法(定义 __ str __ 时),

__ repr __ 在任何地方都可以使用。

  1. __ str __ 必须返回字符串对象,而 __ repr __ 可以返回任何python表达式。
  2. 如果缺少 __ str __ 实现,则 __ repr __ 函数用作回退。如果缺少 __ repr __ 函数实现,则没有回退。
  3. 如果 __ repr __ 函数正在返回对象的String表示,我们可以跳过 __ str __ 函数的实现。
  4. 来源: https://www.journaldev.com/22460/python -str-再版函数

可以通过调用 str(obj)在对象上调用

__ str __ ,并返回一个人类可读的字符串。

可以通过调用 repr(obj)在对象上调用

__ repr __ ,并返回内部对象(对象字段/属性)

这个例子可能会有所帮助:

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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top