1. 程式人生 > >python中__str__與__repr__

python中__str__與__repr__

error: ddr echo open line 沒有 分享 這一 base

(1)背景

python中,對於類(自定義類)的實例對象的默認顯示既沒有太大用處,也不美觀。比如:

1 class adder:
2     def __init__(self,value=0):
3         self.data=value  #初始化數據
4     def __add__(self,other):
5         self.data+=other
6>>> x=adder()
7>>>print(x)
   <__main__.adder. object at 0x.....>
8>>>x
    <__main__.adder object at 0x......>

而通過__str__或者__repr__,可以定制化(costomise)顯示,比如,下面代碼中,在子類中定義了一個返回實例字符的__repr__方法。

技術分享圖片
 1 >>>class addrepr(adder):
 2     def __repr__(self):
 3         return addrepr(%s)% self.data
 4 >>>x=addrepr(2)                               #運行__init__
 5 >>>x+1                                             #
運行__add__ 6 >>>x #運行__repr__ 7 addrepr(3) 8 >>>print(x) #運行__repr__ 9 addrepr(3) 10 >>>str(x),repr(x) #均運行__repr__ 11 (addrepr(3),addrepr(3))
View Code

當類實例化對象被打印或者轉化為字符時,如果定義了__repr__(或者__str__),那麽該__repr__(或者__str__)將被自動調用,這裏__repr__用了最基本的字符格式來將self.data轉化為友好的字符顯示。

(2)為什麽要用兩種顯示方法

雖然__str__與__rer__的作用都是為了獲得更友好的字符顯示,但對於代碼的設計有一些細微的區別。

(a)對於print和str內建函數,程序會首先嘗試__str__函數,如果沒有__str__函數,則嘗試__repr__函數,如果沒有__repr__函數,則選用默認顯示;

(b)在其他情況下,比如交互式回應(interactive echoes),repr函數,和嵌套中,__repr__被調用,一般地,它應該為開發者返回較為詳細的顯示。

下面通過代碼說明兩種方法的不同:

 1 >>>class addstr(adder):
 2         def __str__(self):
 3             return [value:%s]% self.data
 4 >>>x=addstr(3)
 5 >>>x                                                     #默認顯示
 6 <__main__.addstr object at 0x....>                      
 7 >>>print(x)                                              #調用__str__
 8 [value:4]
 9 >>>str(x),repr(x)
10 ([value:4],<__main__.addstr object at 0x...>

(c)如果同時定義了兩種方法,那麽可以在不同情況下,支持不同的顯示。如下面代碼:

 1 >>>class addboth(adder):
 2     def __str__(self):
 3         return [value:%s]%self.data
 4     def __repr__(self):
 5         return addboth(%s)% self.dat
 6 >>>x=addboth(4)
 7 >>>x+1
 8 >>>x                          #調用__repr__
 9 addboth(5)
10 >>>print(x)                 #調用__str__
11 [value:5]
12 >>>str(x),repr(x)         #分別調用__str_,__repr__
13 ([value:5],addboth(5))

(3)使用的三點註意

(a)首先是__str__和__repr__必須均返回字符,返回其他類型,將會報錯,所以必要的話必須確保它們進行字符轉換(比如str,%s)。

(b)根據容器(container)的字符轉換,僅有當對象出現在print的頂層時,才會調用__str__;嵌套在大的對象裏的對象顯示,將仍調用__repr__,下面代碼說明了這一點:

 1 >>>class Printer:
 2     def __init__(self,value):
 3         self.value=value
 4     def __str__(self):
 5         return str(self.value)
 6 >>>objs=[Printer(2),Printer(3)]
 7 >>>for x in objs:print(x)
 8 
 9 2
10 3
11 >>>print(objs)
12 [<__main__.Printer object at 0x....>]
13 >>>objs
14 [<__main__.Printer object at 0x....>]

為確保不論有無容器,在所有情況下顯示定制顯示,用__repr__,不用__str__,用如下代碼進行說明:

 1 >>> class Printer:
 2     def __init__(self,value):
 3         self.val=value
 4     def __repr__(self):                   #如果沒有__str__,調用__repr__
 5         return %s% self.val
 6 
 7     
 8 >>> objs=[Printer(2),Printer(3)]
 9 >>> for x in objs:print(x)
10 
11 2
12 3
13 >>> print(objs)                                 #調用__repr__
14 [2, 3]
15 >>> objs
16 [2, 3]

(c)第三,也是最為微妙的,顯示方法在極少情況下有時又也有可能觸發無限叠代循環(infinite recursion loops),因為一些對象的顯示包括了其他對象的的顯示,而一個顯示觸發了正在被顯示的對象的顯示,因而進入無限循環中。如下代碼:

"""
this scripts is intended to illustrate the infinite recursion loops
caused by __repr__ overloading methods. displaying the value of a method,line10 in this script, can trigger the __repr__
of the class method, then the __repr__ method is called again, and the infinite recursion loops happen.
"""
class Base:
    def __init__(self):
        self.data=1
    def print0(self):
        pass
    def print1(self):
        a=str(getattr(self,print0))  #Caution! getattr(object,attrname),attrname shall be string.
        return a
class Normal(Base):
    def __str__(self):
        return %s% self.print1()
class Recursion(Base):
    def __repr__(self):
        return %s% self.print1()
if __name__==__main__:
    a=Normal()
    b=Recursion()
    print(a)
    try:
        print(b)
    except RecursionError:
        print(A recusion error happens)

運行結果為:

<bound method Base.print0 of <__main__.Normal object at 0x02E68450>>
A recusion error happens

python中__str__與__repr__