str - python__repr__用法




__str__和__repr__之間的區別? (14)

Python中__str____repr__什麼區別?

__str__ (讀作“dunder(雙下劃線)字符串”)和__repr__ (讀作“dunder-repper”(用於“表示”))都是基於對象狀態返回字符串的特殊方法。

如果缺少__repr__提供備份行為。

因此,首先應該編寫一個__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源代碼 ),例如:

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對象所需的一切。 這是由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__一件簡單的事情,因為我們沒有通過從__repr__輸出複制和粘貼,然後打印它來將它分配給變量,並且我們在與另一個對象相同的人類可讀輸出中獲取它:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

我該如何實現它們?

在開發過程中,如果可能的話,您將希望能夠以相同的狀態再現對象。 例如,這是datetime對__repr__如何定義__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 = ", ".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__下一步實現__str__ 。 以下是datetime對象( Python源代碼 )如何實現__str__ ,它很容易做到,因為它已經有一個以ISO格式顯示它的函數:

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

設置__repr__ = __str__

這是對另一個答案的批評,建議設置__repr__ = __str__

設置__repr__ = __str__是愚蠢的 - __repr____repr__的後備,而__repr__是為開發人員在調試中使用而編寫的,應該在編寫__str__之前編寫。

只有在需要對象的文本表示時才需要__str__

結論

為您編寫的對象定義__repr__ ,以便您和其他開發人員在開發時使用它時具有可重現的示例。 當需要人類可讀的字符串表示時,定義__str__

Python __str____repr__什麼區別?


簡而言之, __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__()方法來控制此函數為其實例返回的__repr__()

這是str的文檔:

str(object='')

返回一個包含對象的可打印表示的字符串。 對於字符串,這將返回字符串本身。 與repr(object)的區別在於str(object)並不總是嘗試返回eval()可接受的字符串; 它的目標是返回一個可打印的字符串。 如果沒有給出參數,則返回空字符串''


blog更加清晰

str就像toString。 創建所以你可以打印數據repr就像序列化或pickle。 如果我需要使用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))

__repr__隨處可見,除了定義__str__時的printstr


str - 從給定對象創建新的字符串對象。

repr - 返回對象的規範字符串表示形式。

差異:

STR():

  • 使對象可讀
  • 為最終用戶生成輸出

再版():

  • 需要復制對象的代碼
  • 為開發人員生成輸出

__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

來自effbot的http://pyref.infogami.com/__str__

__str__ “計算對象的”非正式“字符串表示。這與__repr__不同之處在於它不必是有效的Python表達式:可以使用更方便或簡潔的表示。”


優秀的答案已經涵蓋了__str____repr__之間的區別,對我來說,歸結為前者甚至可以被最終用戶讀取,而後者對開發人員盡可能有用。 鑑於此,我發現__repr__的默認實現通常無法實現此目標,因為它省略了對開發人員有用的信息。

出於這個原因,如果我有一個足夠簡單的__str__ ,我通常只是試圖通過以下方式獲得兩全其美:

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

在Hans Petter Langtangen 撰寫的計算科學Python腳本一書的第358頁上,它明確指出了這一點

  • __repr__旨在對象的完整字符串表示;
  • __str__將返回一個很好的字符串進行打印。

所以,我更喜歡把它們理解為

  • repr =重現
  • str = string(表示)

從用戶的角度來看雖然這是我在學習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'

我的經驗法則是: __repr__適用於開發人員, __str__適用於客戶。


簡而言之:

__str__用於顯示對象的字符串表示形式, 以供其他人輕鬆閱讀

__repr__用於顯示對象的字符串表示形式。

假設我想創建一個Fraction類,其中一個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)

簡而言之:

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'

除非您特別採取行動以確保其他方面,否則大多數課程都沒有任何有用的結果:

>>> 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__ ,但反之亦然。

要知道的其他重要花絮:內置容器上的__repr__對它包含的項使用__repr__而不是__str__ 。 並且,儘管在典型的文檔中找到了關於該主題的文字,但幾乎沒有人__repr__將對象的__repr__作為一個字符串, eval可以用它來構建一個相等的對象(它太難了,而且不知道相關模塊是如何實際導入的它實際上是不可能的)。

所以,我的建議:專注於使__str__合理地讓人類可讀,並且__repr__盡可能明確無誤,即使這會干擾模糊的無法實現的目標,即使__repr__的返回值可以作為__eval__輸入!


"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





repr