Python中__str__和__repr_之间有什么区别?


当前回答

优秀的答案已经涵盖了__str__和__repr_之间的差异,对我来说,这归结为前者即使是最终用户也可以阅读,后者对开发人员尽可能有用。考虑到这一点,我发现__repr_的默认实现常常无法实现这一目标,因为它忽略了对开发人员有用的信息。

出于这个原因,如果我有一个足够简单的__str__,我通常只会尝试通过以下方式来达到两全其美:

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

其他回答

Python中__str__和__repr_之间有什么区别?

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

__如果缺少__str__,repr_将提供备份行为。

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

在以后的任何时候,如果认为有必要,可以为实例的用户可读字符串表示编写__str__。

__字符串__

如果打印对象,或将其传递给format、str.format或str,则如果定义了__str__方法,则将调用该方法,否则将使用__repr_。

__代表__

__repr_方法由内置函数repr调用,当它计算返回对象的表达式时,它会在python外壳上响应。

由于它为__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(
      type(self).__module__, type(self).__qualname__, hex(id(self)))

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

<__main__.Foo object at 0x7f80665abdd0>

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

__repr__如何有用?

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

import datetime

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

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

如果我们打印一个datetime对象,我们会看到一种很好的可读(实际上是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对象(Python源代码)是如何实现__str__的,这很容易实现,因为它已经有了一个以ISO格式显示的函数:

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

设置__repr_=__str__?

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

设置__repr__=__str__是愚蠢的-__repr__是__str__的后备方案,在编写__str__之前,应该编写一个__repr___,供开发人员在调试中使用。

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

结论

为您编写的对象定义__repr_,以便您和其他开发人员在开发时使用它时有一个可复制的示例。当需要可读字符串表示时,定义__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.Ddecimal(“1.05”)的结果调用print()时,将打印原始数字;此输出为字符串形式,可以使用__str__()实现。如果我们简单地输入表达式,我们会得到一个decimal.decimal输出-这个输出是以表示形式的,可以用__repr_()实现。所有Python对象都有两种输出形式。字符串形式设计为人类可读。表示形式被设计为生成输出,如果将其提供给Python解释器,将(在可能的情况下)再现所表示的对象。

repr()用于调试或日志。它用于开发人员理解代码。另一方面,str()用户用于非开发人员(QA)或用户。

class Customer:
    def __init__(self,name):
        self.name = name
    def __repr__(self):
        return "Customer('{}')".format(self.name)
    def __str__(self):
        return f"cunstomer name is {self.name}"

cus_1 = Customer("Thusi")
print(repr(cus_1)) #print(cus_1.__repr__()) 
print(str(cus_1)) #print(cus_1.__str__())

直观地理解和永久地区分它们。

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

在示例中看到

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

关于__代表__

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

希望这能帮助你建立具体的基础来探索更多的答案。

(2020条目)

Q: __str__()和__repr___()之间有什么区别?

TL;博士:

LONG

这个问题已经存在了很长一段时间,有很多答案都是正确的(更不用说来自几个Python社区的传说[!])。然而,当谈到本质时,这个问题类似于询问str()和repr()内置函数之间的区别。我将用我自己的语言描述这些差异(这意味着我可能是在“借用”核心Python编程,所以请原谅我)。

str()和repr()都有相同的基本任务:它们的目标是返回Python对象的字符串表示。什么样的字符串表示是它们的区别。

str()和__str__()返回可打印的字符串表示形式对象。。。人类可读/供人类食用的东西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

所以这告诉你Python shell只是eval()是你给它的。明白了吗?现在,让我们repr()两个表达式,看看我们得到了什么。更具体地说,获取其输出并将其转储到解释器中(这一点我们将在后面讨论):

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

哇,他们都工作了?这是因为“foo”虽然是该字符串的可打印字符串表示,但它不是可求值的,但“'fo'”是.123是str()或repr()调用的有效Python int。当我们用这些调用eval()时会发生什么?

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

它之所以有效,是因为123和“foo”是有效的Python对象。另一个关键点是,虽然有时两者都返回相同的东西(相同的字符串表示),但情况并非总是如此。(是的,是的,我可以在eval()工作的地方创建一个变量foo,但这不是重点。)

关于这两对的更多事实

有时,str()和repr()是隐式调用的,这意味着它们是代表用户调用的:当用户执行print(Py1/Py2)或调用print()(Py3+)时,即使用户没有显式调用str((),也会在显示对象之前代表用户进行这样的调用。在Pythonshell(交互式解释器)中,如果在>>提示符下输入变量并按RETURN,解释器将显示对该对象隐式调用repr()的结果。要将str()和repr()连接到__str__()和__repr___(),请认识到对内置函数(即str(x)或repr(y))的调用会导致调用其对象的相应特殊方法:x.__str____通过为Python类实现__str__()和__repr_(),可以重载内置函数(str()和repr()),允许将类的实例传递给str(()和repr()。当进行此类调用时,它们会返回并调用类'__str__()和__repr___()(根据#3)。