摘要:這些基本的特殊方法在類中定義中幾乎總是需要的。和方法對(duì)于一個(gè)對(duì)象,有兩種字符串表示方法。這些都和內(nèi)置函數(shù)以及方法緊密結(jié)合。帶有說明符的合理響應(yīng)是返回。
注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python
有許多特殊方法允許類與Python緊密結(jié)合,標(biāo)準(zhǔn)庫(kù)參考將其稱之為基本,基礎(chǔ)或本質(zhì)可能是更好的術(shù)語(yǔ)。這些特殊方法構(gòu)成了創(chuàng)建與其他Python特性無縫集成的類的基礎(chǔ)。
例如,對(duì)于給定對(duì)象的值,我們需要字符串表示。基類、對(duì)象都有默認(rèn)的__repr__()和__str__()用于提供對(duì)象的字符串表示。遺憾的是,這些默認(rèn)表示不提供信息。我們總是想要覆蓋這些默認(rèn)定義中的一個(gè)或兩個(gè)。我們可以看看__format__(),這個(gè)更復(fù)雜但目的和前面是一樣的。
我們也可以看看其他轉(zhuǎn)換,特別是__hash__()、__bool__()、和__bytes__()。這些方法將一個(gè)對(duì)象轉(zhuǎn)換成數(shù)字、true/false值或字符串的字節(jié)。例如,當(dāng)我們實(shí)現(xiàn)__bool__()時(shí),可以在if語(yǔ)句中使用對(duì)象,如下:if someobject:。
然后,我們可以看看實(shí)現(xiàn)比較操作符的特殊方法__lt__()、__le__()、__eq__()、__ne__()、__gt__()和__ge__()。
這些基本的特殊方法在類中定義中幾乎總是需要的。
最后我們來看看__new__()和__del__(),因?yàn)檫@些方法的用例相當(dāng)復(fù)雜。每當(dāng)我們需要其他基本特殊方法時(shí),是不需要這些的。
我們會(huì)詳細(xì)看看如何添加這些特殊方法來擴(kuò)大一個(gè)簡(jiǎn)單的類定義。我們需要看一下兩個(gè)從對(duì)象繼承的默認(rèn)行為,這樣我們可以了解需要什么樣的覆蓋以及何時(shí)真正需要。
__repr__() 和 __str__() 方法對(duì)于一個(gè)對(duì)象,Python有兩種字符串表示方法。這些都和內(nèi)置函數(shù)__repr__()、__str__()、__print__()以及string.format()方法緊密結(jié)合。
str()方法表示的對(duì)象通常是適用于人理解的,由對(duì)象的__str__()方法創(chuàng)建。
repr()方法表示的對(duì)象通常是適用于解釋器理解的,可能是完整的Python表達(dá)式來重建對(duì)象。文檔中是這樣說的:對(duì)于許多類型,這個(gè)函數(shù)試圖返回一個(gè)字符串,將該字符串傳遞給eval()會(huì)重新生成對(duì)象。
這是由對(duì)象的__repr__()方法創(chuàng)建的。
print()函數(shù)會(huì)使用str()準(zhǔn)備對(duì)象用于打印。
字符串的format()方法也可以訪問這些方法。當(dāng)我們使用{!r}或{!s}格式,我們分別需要__repr__()或__str__()。
首先讓我們看看默認(rèn)實(shí)現(xiàn)。
下面是一個(gè)簡(jiǎn)單的類層次結(jié)構(gòu):
pythonclass Card: insure = False def __init__(self, rank, suit): self.suit = suit self.rank = rank self.hard, self.soft = self._points() class NumberCard(Card): def _points(self): return int(self.rank), int(self.rank)
我們已經(jīng)定義了帶有四個(gè)屬性的兩個(gè)簡(jiǎn)單類。
以下是一個(gè)與其中一個(gè)類對(duì)象的交互:
>>> x=NumberCard( "2", "?") >>> str(x) "<__main__.NumberCard object at 0x1013ea610>" >>> repr(x) "<__main__.NumberCard object at 0x1013ea610>" >>> print(x) <__main__.NumberCard object at 0x1013ea610>
從這個(gè)輸出知道默認(rèn)的__str__()和__repr__()實(shí)現(xiàn)不是很豐富。
當(dāng)我們需要覆蓋__str__()和__repr__()時(shí)我們考慮下面兩個(gè)廣泛的設(shè)計(jì)用例:
非集合對(duì)象:一個(gè)不包含其他對(duì)象集合的“簡(jiǎn)單”對(duì)象,通常不涉及非常復(fù)雜格式的集合。
集合對(duì)象:一個(gè)包含一組更復(fù)雜格式的對(duì)象。
1. 非集合__str__()和__repr__()正如我們之前看到的,__str__()和__repr__()的輸出不是很豐富。我們幾乎總是需要覆蓋它們。以下是當(dāng)沒有包含集合的時(shí)候覆蓋__str__()和__repr__()的方法。這些方法從屬于之前定義的Card類:
pythondef __repr__(self): return "{__class__.__name__}(suit={suit!r}, rank={rank!r})".format( __class__=self.__class__, **self.__dict__) def __str__(self): return "{rank}{suit}".format(**self.__dict__)
這兩個(gè)方法依賴于傳遞內(nèi)部對(duì)象的實(shí)例變量__dict__()給format()函數(shù)。對(duì)于對(duì)象使用__slots__是不適合的;通常,這些是不可變的對(duì)象。在格式說明符中使用名稱會(huì)使得格式化更顯式。當(dāng)然也使得格式模板更長(zhǎng)了。在__repr__()中,我們傳遞內(nèi)部__dict__加上對(duì)象的__class__作為關(guān)鍵字參數(shù)值給format()函數(shù)。
模板字符串使用兩種格式說明符:
{__class__.__name__}模板也可以寫成{__class__.__name__!s}從而當(dāng)只提供簡(jiǎn)單字符串的類名時(shí)變得更顯式。
{suit!r}和{rank!r }模板都使用!r格式說明符生成屬性值的repr()方法。
在__str__()中,我們只有傳遞內(nèi)部__dict__對(duì)象。格式化使用隱式的{!s}格式說明符來生成屬性值的str()方法。
2. 集合__str__()和__repr__()當(dāng)包含一個(gè)集合時(shí),我們需要格式化集合中的每個(gè)項(xiàng)目以及整個(gè)容器。以下是帶有__str__()和__repr__()方法的簡(jiǎn)單集合:
pythonclass Hand: def __init__(self, dealer_card, *cards): self.dealer_card = dealer_card self.cards = list(cards) def __str__(self): return ", ".join(map(str, self.cards)) def __repr__(self): return "{__class__.__name__}({dealer_card!r}, {_cards_str})".format( __class__=self.__class__, _cards_str=", ".join( map(repr, self.cards)),**self.__dict__)
__str__()方法是一個(gè)簡(jiǎn)單的設(shè)計(jì),如下:
映射str()到集合中的每一項(xiàng)。這將在生成的每個(gè)字符串值上創(chuàng)建一個(gè)迭代器。
使用", ".join()合并所有項(xiàng)的字符串到一個(gè)長(zhǎng)字符串中。
__repr__()方法是一個(gè)多部分的設(shè)計(jì),如下:
映射repr()到集合中的每一項(xiàng)。這將在生成的每個(gè)字符串值上創(chuàng)建一個(gè)迭代器。
使用", ".join()合并所有項(xiàng)的字符串。
創(chuàng)建一組帶有__class__的關(guān)鍵字、集合字符串和來自__dict__的各種屬性。我們已經(jīng)命名集合字符串為_card_str,與現(xiàn)有的屬性不沖突。
使用"{__class__.__name__}({dealer_card!r}, {_card_str})".format()將類名與項(xiàng)目值的長(zhǎng)字符串結(jié)合。我們使用!r進(jìn)行格式化以確保屬性也使用了repr()轉(zhuǎn)換。
在某些情況下,這可以使一些事情變得稍微簡(jiǎn)單些。位置參數(shù)的格式化可以一定程度上縮短模板字符串的長(zhǎng)度。
__format__() 方法和內(nèi)置函數(shù)format()一樣,string.format()使用__format__()方法。這兩個(gè)接口都是用來從給定對(duì)象得到像樣的字符串的方式。
以下是將參數(shù)提供給__format__()的兩種方法:
someobject.__format__(""):發(fā)生在應(yīng)用程序使用format(someobject)或等價(jià)的"{0}".format(someobject)的時(shí)候。在這些情況下,提供了長(zhǎng)度為零的字符串說明符。這會(huì)產(chǎn)生一個(gè)默認(rèn)格式。
someobject.__format__(specification):發(fā)生在應(yīng)用程序使用format(someobject, specification)或等價(jià)的"{0:specification}".format(someobject)的時(shí)候。
請(qǐng)注意,類似于"{0!r}".format()或"{0!s}".format()的方法沒有使用__format__()方法。它們直接使用了__repr__()或__str__()。
帶有""說明符的合理響應(yīng)是返回str(self)。它對(duì)各種對(duì)象的字符串提供了顯式的一致性表示。
格式說明符必須都是文本,且在格式字符串的":"之后。當(dāng)我們寫"{0:06.4f}",06.4f是適用于第0項(xiàng)參數(shù)列表的格式說明符。
Python標(biāo)準(zhǔn)庫(kù)文檔中的6.1.3.1節(jié)定義了一個(gè)復(fù)雜的數(shù)值說明符作為九個(gè)部分字符串,這是格式說明符的一種迷你語(yǔ)言。有如下語(yǔ)法:
[[fill]align][sign][#][0][width][,][.precision][type]
我們可以用正則表達(dá)式解析這些標(biāo)準(zhǔn)說明符,如下面代碼片段所示:
re.compile( r"(?P.?[<>=^])?" "(?P [-+ ])?" "(?P #)?" "(?P 0)?" "(?P d*)" "(?P ,)?" "(?P .d*)?" "(?P [bcdeEfFgGnosxX%])?" )
這個(gè)正則將說明符拆分成八組。第一組和原說明符一樣有fill和alignment字段。我們可以使用這些得出我們已定義類的格式化數(shù)值數(shù)據(jù)。
然而,Python的格式說明符迷你語(yǔ)言可能不適用于我們的類定義。因此,我們需要定義我們自己的說明符迷你語(yǔ)言并在類的__format__方法中執(zhí)行。如果我們定義數(shù)值類型,我們應(yīng)該堅(jiān)持預(yù)定義的迷你語(yǔ)言。然而,對(duì)于其他類型則沒有理由再堅(jiān)持預(yù)定義的語(yǔ)言。
作為一個(gè)示例,這里有個(gè)微不足道的語(yǔ)言,使用字符%r和%s分別給我們展示牌值和花色。在結(jié)果字符串中%%字符變成%。所有其他字符是重復(fù)的。
我們可以通過格式化擴(kuò)展我們的Card類,如下面代碼片段所示:
pythondef __format__(self, format_spec): if format_spec == "": return str(self) rs = format_spec.replace("%r", self.rank).replace("%s", self.suit) rs = rs.replace("%%", "%") return rs
這個(gè)定義會(huì)檢查格式說明符。如果沒有說明符,則使用str()函數(shù)。如果提供了一個(gè)說明符,會(huì)合攏牌值、花色和任何%字符格式說明符,將其轉(zhuǎn)化為輸出字符串。
這允許我們像下面這樣格式化Card:
pythonprint( "Dealer Has {0:%r of %s}".format(hand.dealer_card))
格式說明符("%r of %s")被作為format的參數(shù)傳遞給我們的__format__()方法。使用這個(gè),我們能夠提供一個(gè)一致的接口來表示我們已經(jīng)定義的類的對(duì)象。
或者,我們可以定義如下:
pythondefault_format = "some specification" def __str__(self): return self.__format__(self.default_format) def __format__(self, format_spec): if format_spec == "": format_spec = self.default_format # process the format specification.
這個(gè)的優(yōu)勢(shì)在于把所有字符串放置到__format__()方法,而不是分開到的__format__()和__str__()。劣勢(shì)在于,我們不總是需要實(shí)現(xiàn)__format__(),但我們幾乎總是需要實(shí)現(xiàn)__str__()。
1. 嵌套格式化說明符string.format()方法可以處理嵌套的{}實(shí)例來執(zhí)行簡(jiǎn)單的關(guān)鍵字置換到格式說明符中。這個(gè)置換完成,會(huì)創(chuàng)建最終格式字符串并傳遞給類的__format__()方法。這種嵌套置換通過參數(shù)化通用說明符簡(jiǎn)化了某些相對(duì)復(fù)雜的數(shù)值格式。
下面的例子,我們可以在format參數(shù)中很容易的修改width:
pythonwidth = 6 for hand, count in statistics.items(): print( "{hand} {count:{width}d}".format(hand=hand, count=count, width=width))
我們定義了一個(gè)通用的格式,"{hand:%r%s } {count:{width}d}",這需要一個(gè)width參數(shù)讓它變成適用的格式說明符。
為format()方法提供width=參數(shù)的值被用于替代{width}嵌套說明符。一旦被替換,最終格式會(huì)作為一個(gè)整體提供給__format__()方法。
2. 集合與委托格式說明符格式化一個(gè)包括集合的復(fù)雜對(duì)象,有兩個(gè)格式化問題:如何格式化整體對(duì)象以及如何格式化集合中的項(xiàng)目。當(dāng)我們看到Hand,例如,我們看到我們有多帶帶的Card類集合。我們需要Hand委托格式化細(xì)節(jié)給多帶帶的Card實(shí)例。
下面是一個(gè)適用于Hand的__format__()方法:
pythondef __format__(self, format_specification): if format_specification == "": return str(self) return ", ".join("{0:{fs}}".format(c, fs=format_specification) for c in self.cards)
format_specification參數(shù)將用于每個(gè)Hand集合里面的Card實(shí)例。格式說明符"{0:{fs}}"使用嵌套格式說明符技術(shù)將format_specification字符串置入到應(yīng)用于Card實(shí)例的創(chuàng)建。使用這種方法我們可以格式化Hand對(duì)象、player_hand,如下所示:
python"Player: {hand:%r%s}".format(hand=player_hand)
這將應(yīng)用%r%s格式說明符到Hand對(duì)象中的Card實(shí)例。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/45391.html
摘要:比較運(yùn)算符方法有六個(gè)比較運(yùn)算符。根據(jù)文檔,其映射工作如下第七章創(chuàng)建數(shù)字我們會(huì)再次回到比較運(yùn)算符這塊。同一個(gè)類的對(duì)象的比較實(shí)現(xiàn)我們來看看一個(gè)簡(jiǎn)單的同一類的比較通過觀察一個(gè)更完整的類現(xiàn)在我們已經(jīng)定義了所有六個(gè)比較運(yùn)算符。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python __bool__()方法 Python對(duì)假有個(gè)很...
摘要:有三個(gè)用例通過和方法定義相等性檢測(cè)和值不可變對(duì)象對(duì)于有些無狀態(tài)對(duì)象,例如這些不能被更新的類型。請(qǐng)注意,我們將為不可變對(duì)象定義以上兩個(gè)。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python __hash__() 方法 內(nèi)置hash()函數(shù)會(huì)調(diào)用給定對(duì)象的__hash__()方法。這里hash就是將(可能是復(fù)雜的)值縮減...
摘要:當(dāng)引用計(jì)數(shù)為零,則不再需要該對(duì)象且可以銷毀。這表明當(dāng)變量被刪除時(shí)引用計(jì)數(shù)正確的變?yōu)榱恪7椒ㄖ荒茉谘h(huán)被打破后且引用計(jì)數(shù)已經(jīng)為零時(shí)調(diào)用。這兩步的過程允許引用計(jì)數(shù)或垃圾收集刪除已引用的對(duì)象,讓弱引用懸空。這允許在方法設(shè)置對(duì)象屬性值之前進(jìn)行處理。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python __del__()方法 ...
摘要:第二章與的無縫集成基本特殊方法筆記中有有一些特殊的方法它們?cè)试S我們的類和更好的集成和方法通常方法表示的對(duì)象對(duì)用戶更加友好這個(gè)方法是有對(duì)象的方法實(shí)現(xiàn)的什么時(shí)候重寫跟非集合對(duì)象一個(gè)不包括其他集合對(duì)象的簡(jiǎn)單對(duì)象這類對(duì)象格式通常不會(huì)特別復(fù) 第二章 與Python的無縫集成----基本特殊方法.(Mastering Objecting-oriented Python 筆記) python中有有一...
閱讀 1353·2023-04-26 00:35
閱讀 2723·2023-04-25 18:32
閱讀 3370·2021-11-24 11:14
閱讀 780·2021-11-22 15:24
閱讀 1428·2021-11-18 10:07
閱讀 6535·2021-09-22 10:57
閱讀 2782·2021-09-07 09:58
閱讀 3572·2019-08-30 15:54