很多時候我們在創建一個類的時候,在終端打印類或者查看的時候一般都不會得到一個太滿意的結果
class T:
def __init__(self):
self.color="red"
self.count = 2
t = T()
t
>>> <T object at 0x0000000003444E10>
print(t)
>>> <T object at 0x0000000003444E10>
類轉化為字符串,直接打印結果一般都不是我們想要的東西,僅僅包含了類的名稱以及實例的 ID (理解為 Python 對象的內存地址即可),例如<T object at 0x0000000003444E10> ,這樣類默認轉化為字符串根本不能得到我們想要的關於屬性信息等的相關東西,只能通過手動打印才能進一步獲取到更多的信息,例如print(t.color)
使用 __str__ 實現類到字符串的轉化
不用自己另外的定義方法,和java的toString的方法類似,可以在類里面實現__str__和__repr__方法,從而自已定義類的字符串描述,下面具體看看這兩種方式是怎么工作的。
首先,我們先加一個 __str__ 方法到前面的類中看看情況。
class T: def __str__(self): return self.color+"__str__" def __init__(self): self.color="red" self.count = 2 t = T() t >>> <T object at 0x0000000003444E10> print(t) >>> red__str__
查看 t的時候的輸出仍然和之前一樣,輸出內存地址信息,不過打印 t的時候返回的內容和新加的 __str__ 方法的返回一致。類的 __str__ 方法會在某些 需要將對象轉為字符串的時候被調用。
比如下面這些情況,需要將對象轉為字符串
print(t) print(str(t)) print("{}".format(t))
使用 __repr__ 也有類似的效果
會發現,在使用__str__方法的時候,直接在終端查看t對象的時候,輸出的時候仍然是內存地址,這是因為在python3中有兩種方式控制對象轉字符串,第一種就是__str__,第二種就是__repr__,兩種的工作方式大體相同,只是調用的時機不同。下面通過一個簡單的例子看看__repr__方法
class T: def __repr__(self): return self.color+"__repr__" def __str__(self): return self.color+"__str__" def __init__(self): self.color="red" self.count = 2 t = T() t >>> red__repr__ print(t) >>> red__str__ print(str(t)) >>> red__str__ print("{}".format(t)) >>> red__str__ print(str(["d","f",t])) >>> ['d', 'f', red__repr__]
通過如上的例子可以看出,當直接查看對象的時候調用的是__repr__方法,對象需要轉字符串的時候調用的是__str__方法,但是當字典列表等容器的時候調用的還是__repr__方法
如果我們需要顯示的指定以何種方式進行類到字符串的轉化,我們可以使用內置的 str() 或 repr() 方法,它們會調用類中對應的雙下划線方法。除了字典、列表等作為容器的時候print(str(["d","f",t])),雖然調用的是str()方法,可是容器是列表,所以對象t轉為字符串時調用的就是__repr__
__str__ 和 __repr__ 的差別
那么他們的區別具體的在哪里,帶着這個問題我們python的標准庫, 其中datetime.date 這個類是怎么在使用這兩個方法的。
import datetime today = datetime.datetime.today() print(str(today)) >>> 2019-10-20 20:59:47.003003 print(repr(today)) >>> datetime.datetime(2019, 10, 20, 20, 59, 47, 3003)
__str__ 的返回結果可讀性強。也就是說,__str__ 的意義是得到便於人們閱讀的信息,就像上面的 '2019-10-20 20:59:47.003003' 一樣。
__repr__ 的返回結果應更准確。怎么說,__repr__ 存在的目的在於調試,便於開發者使用。將 __repr__ 返回的方式直接復制到命令行上,是可以直接執行的。
為什么每個類都最好有一個 __repr__ 方法
如果你想保證每個類到字符串都有一個有效的自定義轉換方式,你需要重寫__str__或者__repr__中的一個方法,如果沒有寫__str__方法,python就會去找__repr__方法,所以至少添加一個
class T: def __repr__(self): return (self.color) def __init__(self,color): self.color = color t = T("red") print(t) >>> red
t
>>> red
print(str(t))
>>> red
實現了 __repr__ 方法后,當我們查看類的實例或者直接調用 repr() 方法,就能得到一個比較滿意的結果了。打印或直接調用str()等類轉字符串的操作都會得到相同的結果,因為__str__的默認實現就是調用__repr__方法。
- 我們可以使用__str__ 和 __repr__中的任意一個方法定義類到字符串的轉化方式,不需要手動的打印某些屬性和一些額外的信息
- 一般來說__str__的可讀性更強,而__repr__的返回結果更具有准確性,更加的適合開發者
- 我們在寫類的時候,最好至少添加一個__repr__方法,來保證類到字符串的轉換具有自定義的有效性,__str__是可選的,因為在默認情況下,__Str__方法默認實現調用的是__repr__方法,所以在對象轉字符串時候,找到底層str方法之后,會調用重寫的__repr__方法
也就是說,
直接查看字符串的時候調用的是__repr__方法;
對象在轉字符串的時候:如果容器是字典或者列表調用的是__repr__方法;如果是其他情況則默認調用的是底層的__Str__方法。__str__如果被重寫調用的則是重寫之后__Str__,就和__repr__沒有關系了,如果沒有被重寫,則調用的是底層__str__方法,底層方法默認實現方式是調用了__repr__ 方法,之后查看__repr__是否被重寫,重寫則調用重寫之后的,否則調用底層的__repr__,最后執行轉為字符串
如果打印str(t)則默認調用的是__str__,如果直接打印repr(t)則默認調用的是__repr__方法