geekdoc-python-zh/docs/pythoncentral/what-is-the-difference-betw...

5.0 KiB
Raw Permalink Blame History

Python 中 strrepr 有什么区别

原文:https://www.pythoncentral.io/what-is-the-difference-between-str-and-repr-in-python/

Python 中 strrepr 的用途

在我们深入讨论之前,让我们来看看 Python 的官方文档中关于这两个函数的内容:

object.__repr__(self):由repr()内置函数和字符串转换(反引号)调用,计算对象的“正式”字符串表示。 object.__str__(self):由str()内置函数和 print 语句调用,计算对象的“非正式”字符串表示。

引用自 Python 的数据模型

从官方文档中,我们知道__repr____str__都是用来“表示”一个对象的。__repr__应该是“正式”代表,而__str__是“非正式”代表。

那么Python 默认的任何对象的__repr____str__实现是什么样子的呢?

例如,假设我们有一个int x和一个str y,我们想知道这两个对象的__repr____str__的返回值:


>>> x = 1

>>> repr(x)

'1'

>>> str(x)

'1'

>>> y = 'a string'

>>> repr(y)

"'a string'"

>>> str(y)

'a string'

虽然int xrepr()str()的返回值是相同的,但是您应该注意到str y的返回值之间的差异。认识到str对象的默认实现__repr__可以作为eval的参数调用,返回值将是有效的str对象,这一点很重要:


>>> repr(y)

"'a string'"

>>> y2 = eval(repr(y))

>>> y == y2

True

__str__的返回值甚至不是一个可以被 eval 执行的有效语句:


>>> str(y)

'a string'

>>> eval(str(y))

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

File "<string>", line 1

a string

^

SyntaxError: unexpected EOF while parsing

因此,如果可能的话,对象的“正式”表示应该可以被 eval() 调用并返回相同的对象。如果不可能的话,比如对象的成员引用自己,导致无限循环引用,那么__repr__应该是明确的,包含尽可能多的信息。


>>> class ClassA(object):

...   def __init__(self, b=None):

...     self.b = b

...

...   def __repr__(self):

...     return '%s(%r)' % (self.__class__, self.b)

...

>>>

>>> class ClassB(object):

...   def __init__(self, a=None):

...     self.a = a

...

...   def __repr__(self):

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

...

>>> a = ClassA()

>>> b = ClassB(a=a)

>>> a.b = b

>>> repr(b)

RuntimeError: maximum recursion depth exceeded while calling a Python object

你可以用不同的方式定义ClassB.__repr__,而不是完全遵循__repr__ClassB的要求,这将导致无限递归问题,其中a.__repr__调用b.__repr__,而b.__repr__调用a.__repr__,后者调用b.__repr__,,如此循环往复。尽可能多地显示对象信息的方法与有效的 eval-constrained__repr__一样好。


>>> class ClassB(object):

...   def __init__(self, a=None):

...     self.a = a

...

...   def __repr__(self):

...     return '%s(a=a)' % (self.__class__)

...
> > > a = class a()
>>>b = class b(a = a)
>>>a . b = b
>>>repr(a)
<class ' _ _ main _ _主要的主要的class '>(a = a))"
>>>repr(b)
"<class ' _ _ main _ _。>(a = a)

因为__repr__是对象的官方表示,所以您总是希望调用"repr(an_object)"来获得关于对象的最全面的信息。然而,有时__str__也是有用的。因为__repr__可能太复杂而无法检查所讨论的对象是否复杂(想象一个对象有十几个属性)__str__有助于快速概述复杂的对象。例如,假设您想要检查一个冗长日志文件中间的datetime对象,以找出用户照片的datetime不正确的原因:


>>> from datetime import datetime

>>> now = datetime.now()

>>> repr(now)

'datetime.datetime(2013, 2, 5, 4, 43, 11, 673075)'

>>> str(now)

'2013-02-05 04:43:11.673075'

现在的__str__表示看起来比从__repr__生成的正式表示更清晰、更易读。有时候,能够快速理解对象中存储的内容对于理解复杂程序的“大”图景是很有价值的。

Python 中 strrepr 之间的问题

需要记住的一个重要问题是,容器的__str__使用包含的对象的__repr__


>>> from datetime import datetime

>>> from decimal import Decimal

>>> print((Decimal('42'), datetime.now()))

(Decimal('42'), datetime.datetime(2013, 2, 5, 4, 53, 32, 646185))

>>> str((Decimal('42'), datetime.now()))

"(Decimal('42'), datetime.datetime(2013, 2, 5, 4, 57, 2, 459596))"

因为 Python 更喜欢明确性而不是可读性,所以元组的__str__调用调用包含的对象的__repr__,即对象的“正式”表示。虽然正式表示比非正式表示更难阅读,但它是明确的,并且对错误更健壮。

Python 中 strrepr 之间的提示和建议

  • 为你实现的每个类实现__repr__。不应该有任何借口。
  • 对于你认为可读性对不模糊性更重要的类,实现__str__