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


当前回答

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

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

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

其他回答

摘自《流利的Python》一书:

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

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

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__())

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

因此,我建议设置__repr_=__str__。原因是str(list)在元素上调用repr(我认为这是Python最大的设计缺陷之一,Python 3没有解决)。实际的repr可能对打印([your,objects])的输出没有太大帮助。

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

需要记住的一点是,容器的__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_,即对象的“形式”表示。虽然正式表示比非正式表示更难理解,但它是明确的,并且对bug更为健壮。