摘要:比較運(yùn)算符方法有六個(gè)比較運(yùn)算符。根據(jù)文檔,其映射工作如下第七章創(chuàng)建數(shù)字我們會(huì)再次回到比較運(yùn)算符這塊。同一個(gè)類的對(duì)象的比較實(shí)現(xiàn)我們來(lái)看看一個(gè)簡(jiǎn)單的同一類的比較通過(guò)觀察一個(gè)更完整的類現(xiàn)在我們已經(jīng)定義了所有六個(gè)比較運(yùn)算符。
__bool__()方法注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python
Python對(duì)假有個(gè)很好的定義。參考手冊(cè)列出了大量的值來(lái)被檢測(cè)為False。這包括諸如:False、0、""、[]、()、{}。大多數(shù)其他對(duì)象將被檢測(cè)為True。
通常,我們會(huì)用一個(gè)簡(jiǎn)單的語(yǔ)句檢查一個(gè)對(duì)象“不空”,如下所示:
if some_object: process(some_object)
隱藏在內(nèi)部的是內(nèi)置函數(shù)__bool__()的工作。這個(gè)函數(shù)依賴于一個(gè)給定對(duì)象的__bool__()方法。
默認(rèn)的__bool__()方法返回True。我們可以看如下代碼:
>>> x = object() >>> bool(x) True
對(duì)于大多數(shù)類,這是非常有效的。大多數(shù)對(duì)象不會(huì)是False。然而,對(duì)于集合這是不合適的。空集合應(yīng)該相當(dāng)于False。非空集合則返回True。我們可能需要添加一個(gè)這樣的方法到我們的Deck對(duì)象。
如果我們包裝一個(gè)列表,我們需要如下操作:
def __bool__(self): return bool(self._cards)
它委托布爾函數(shù)到內(nèi)部_cards集合。
如果我們擴(kuò)展列表,我們需要如下操作:
def __bool__(self): return super().__bool__(self)
它委托到__bool__()函數(shù)的超類定義。
在這兩種情況下,我們特意地委托布爾檢測(cè)。在包裝那個(gè)例子,我們委托給集合。在擴(kuò)展的例子,我們委托給超類。無(wú)論哪種方式,包裝或擴(kuò)展,空集合將是False。這將給我們一種途徑去看Deck對(duì)象是否已經(jīng)完全處理完且是空的。
我們可以按照如下代碼片段所示去做:
d = Deck() while d: card= d.pop() # process the card
此循環(huán)將處理所有的牌,在整副牌都沒(méi)有了的時(shí)候不會(huì)出現(xiàn)IndexError異常。
__bytes__()方法有時(shí)候會(huì)出現(xiàn)將一個(gè)對(duì)象轉(zhuǎn)換成字節(jié)的情況。我們將在第2部分《持久化和序列化》中詳細(xì)看看相關(guān)內(nèi)容。
在最常見(jiàn)的情況下,應(yīng)用程序可以創(chuàng)建一個(gè)字符串表示,Python IO類內(nèi)置的編碼功能可以將字符串轉(zhuǎn)換成字節(jié)。幾乎任何情況下都能完成的很好。唯一的例外是當(dāng)我們定義了一種新的字符串。在這種情況下,我們需要定義該字符串編碼。
bytes()函數(shù)可以做很多事情,但這取決于它的參數(shù):
bytes(integer):返回給定整數(shù)個(gè)0x00的不可變字節(jié)對(duì)象。
bytes(string):將給定字符串編碼成字節(jié)。額外的編碼參數(shù)和錯(cuò)誤處理將定義編碼處理的細(xì)節(jié)。
bytes(something):這將調(diào)用something.__bytes__()來(lái)創(chuàng)建一個(gè)字節(jié)對(duì)象。這里將不會(huì)使用編碼或錯(cuò)誤參數(shù)。
基本object類沒(méi)有定義__bytes__()。這意味著我們的類默認(rèn)不提供__bytes__()方法。
有一些特殊的情況下,我們可能需要有一個(gè)在寫入到文件之前被直接編碼到字節(jié)中的對(duì)象。通常是簡(jiǎn)單的字符串并允許str類型為我們生成字節(jié)。在處理字節(jié)時(shí),重要的是要注意,沒(méi)有簡(jiǎn)單的方法從文件或接口來(lái)解碼。內(nèi)置的bytes類只會(huì)解碼字符串,不是我們獨(dú)有的新對(duì)象。我們可能需要從字節(jié)解碼來(lái)解析字符串。或者,我們可能需要使用struct模塊顯式地解析字節(jié),通過(guò)解析好的值創(chuàng)建獨(dú)有對(duì)象。
我們看看編碼和解碼Card成字節(jié)。有52個(gè)牌值,每張牌可以打包到一個(gè)字節(jié)。然而,我們已經(jīng)選擇使用一個(gè)字符代表suit和一個(gè)字符來(lái)表示rank。此外,我們需要正確地重構(gòu)Card子類,所以我們必須編碼幾件事情:
Card(AceCard, NumberCard, FaceCard)子類
子類定義的__init__()的參數(shù)
注意,我們的替代方法__init__()將一個(gè)牌值轉(zhuǎn)換成一個(gè)字符串,失去原來(lái)的數(shù)值。為了一個(gè)可逆的字節(jié)編碼,我們需要重構(gòu)這個(gè)原始牌值。
下面是__bytes__()的實(shí)現(xiàn),它返回一個(gè)utf-8編碼的Cards類、rank和suit:
def __bytes__(self): class_code = self.__class__.__name__[0] rank_number_str = {"A": "1", "J": "11", "Q": "12", "K": "13"}. get(self.rank, self.rank) string = "("+" ".join([class_code, rank_number_str, self.suit,]) + ")" return bytes(string, encoding="utf8")
以上通過(guò)創(chuàng)建一個(gè)Card對(duì)象的字符串表示,然后編碼字符串到字節(jié)才能起作用。這通常是最簡(jiǎn)單、最靈活的方法。
當(dāng)我們有一堆字節(jié)的時(shí)候,可以解碼字符串,然后將字符串解析到新的Card對(duì)象。下面是一個(gè)可以用于從字節(jié)創(chuàng)建一個(gè)Card對(duì)象的方法:
def card_from_bytes(buffer): string = buffer.decode("utf8") assert string[0] == "(" and string[-1] == ")" code, rank_number, suit = string[1:-1].split() class_ = {"A": AceCard, "N": NumberCard, "F": FaceCard}[code] return class_(int(rank_number), suit)
在前面的代碼中,我們將字節(jié)解碼為一個(gè)字符串。然后我們將該字符串解析為各個(gè)值。從這些值,我們可以定位類且構(gòu)建原始Card對(duì)象。
我們可以構(gòu)建Card對(duì)象的字節(jié)表示,如下:
b = bytes(someCard)
我們可以通過(guò)字節(jié)重構(gòu)Card對(duì)象,如下:
someCard = card_from_bytes(b)
重要的是要注意,外部字節(jié)表示通常是具有挑戰(zhàn)性的設(shè)計(jì)。我們創(chuàng)建一個(gè)對(duì)象狀態(tài)表示。Python已經(jīng)有很多對(duì)我們類定義工作的很好的表示。
通常是使用pickle或json模塊比發(fā)明低級(jí)的字節(jié)來(lái)表示一個(gè)對(duì)象要更好。這是第九章《序列化和存儲(chǔ)JSON、YAML、Pickle、CSV和XML》的主要內(nèi)容。
比較運(yùn)算符方法Python有六個(gè)比較運(yùn)算符。這些操作符有特殊的方法實(shí)現(xiàn)。根據(jù)文檔,其映射工作如下:
x < y calls x.__lt__(y)
x <= y calls x.__le__(y)
x == y calls x.__eq__(y)
x != y calls x.__ne__(y)
x > y calls x.__gt__(y)
x >= y calls x.__ge__(y)
第七章《創(chuàng)建數(shù)字》我們會(huì)再次回到比較運(yùn)算符這塊。
有一些關(guān)于哪個(gè)操作符被真實(shí)實(shí)現(xiàn)的額外規(guī)則。這些規(guī)則是基于左邊對(duì)象的類所需的特殊方法。如果沒(méi)有,Python可以改變順序來(lái)嘗試另一種操作。
這里有兩個(gè)基本規(guī)則
首先,左邊的操作數(shù)是由操作符的實(shí)現(xiàn)方法來(lái)檢查的:A < B意味著A.__lt__(B)。
第二,右邊的操作數(shù)是由相反的操作符的實(shí)現(xiàn)方法來(lái)檢查的:A < B意味著B.__gt__(A)。
罕見(jiàn)的例外發(fā)生在右操作數(shù)是左操作數(shù)的一個(gè)子類;然后,右操作數(shù)是第一個(gè)被檢查的,允許子類覆蓋超類。
我們可以看到這是如何工作的當(dāng)一個(gè)類只有一個(gè)操作符的時(shí)候,然后供其他操作符使用。
以下是我們可以使用的部分類:
class BlackJackCard_p: def __init__(self, rank, suit): self.rank = rank self.suit = suit def __lt__(self, other): print("Compare {0} < {1}".format(self, other)) return self.rank < other.rank def __str__(self): return "{rank}{suit}".format(**self.__dict__)
這是21點(diǎn)的比較規(guī)則,花色不重要。我們省略了比較的方法來(lái)了解當(dāng)操作符丟失的時(shí)候Python是如何撤回的。這個(gè)類允許我們執(zhí)行<比較。有趣的是,Python還可以通過(guò)切換參數(shù)順序來(lái)使用>比較。換句話說(shuō),x < y ≡ y > x。這是鏡像反射規(guī)則;我們將在第七章《創(chuàng)造數(shù)字》再次見(jiàn)到它。
我們將看到試圖評(píng)估不同的比較操作。創(chuàng)建兩個(gè)Cards類且比以不同的方式較它們,如下代碼片段所示:
>>> two = BlackJackCard_p(2, "?") >>> three = BlackJackCard_p(3, "?") >>> two < three Compare 2? < 3? True >>> two > three Compare 3? < 2? False >>> two == three False >>> two <= three Traceback (most recent call last): File "", line 1, in TypeError: unorderable types: BlackJackCard_p() <= BlackJackCard_p()
從這,我們可以看到two < three映射到two.__lt__(three)。
然而,對(duì)于two > three、沒(méi)有__gt__()方法定義;Python使用three.__lt__(two)作為一個(gè)后備計(jì)劃。
默認(rèn)情況下,__eq__()方法是繼承自object;它比較對(duì)象ID;對(duì)象將有==和!=檢測(cè),如下:
>>> two_c = BlackJackCard_p(2, "?") >>> two == two_c False
我們可以看到結(jié)果并不是我們所期待的。我們會(huì)經(jīng)常需要覆蓋默認(rèn)的__eq__()實(shí)現(xiàn)。
同樣,操作符之間沒(méi)有邏輯聯(lián)系。在數(shù)學(xué)上,只要兩個(gè)就可以派生所有必要的比較。Python不會(huì)自動(dòng)這樣做。相反,Python默認(rèn)處理以下四對(duì)相反的檢測(cè):
x < y ≡ y > x x ≤ y ≡ y ≥ x x = y ≡ y = x x =? y ≡ y =? x
這意味著我們必須至少?gòu)乃膶?duì)中提供一個(gè)。例如,我們可以提供__eq__()、__ne__()、__lt__()和__le__()。
@functools.total_ordering裝飾器克服了默認(rèn)限制,并從__eq__()和__lt__()、__le__()、__gt__()中任意的一個(gè),推導(dǎo)出其余的比較。我們將在第7章《創(chuàng)造數(shù)字》再次討論這個(gè)。
1. 設(shè)計(jì)比較在比較運(yùn)算符有兩個(gè)顧慮:
顯而易見(jiàn)的問(wèn)題是怎樣比較相同類的兩個(gè)對(duì)象
不太明顯的問(wèn)題是怎樣比較不同類的對(duì)象
對(duì)于一個(gè)類有多個(gè)屬性,我們考慮比較運(yùn)算符的時(shí)候經(jīng)常模棱兩可。可能不是很清楚我們要比較什么。
再次考慮不起眼的撲克牌。表達(dá)式如card1 == card2顯然是為了比較rank和suit。對(duì)嗎?或者總是為真?終究,suit在21點(diǎn)沒(méi)有意義。
如果我們想決定Hand對(duì)象是否可以分牌,我們最好看下這兩個(gè)代碼片段。以下是第一個(gè)代碼片段:
if hand.cards[0] == hand.cards[1]
下面是第二個(gè)代碼片段:
if hand.cards[0].rank == hand.cards[1].rank
雖然有一個(gè)是更短,簡(jiǎn)潔并不總是最好的。如果我們定義相等只考慮rank,我們將很難定義單元測(cè)試,因?yàn)楫?dāng)一個(gè)單元測(cè)試應(yīng)該關(guān)注完全正確的牌時(shí),一個(gè)簡(jiǎn)單的TestCase.assertEqual()方法會(huì)容忍各種各樣的牌。
表達(dá)式如card1 < = 7顯然是為了比較rank。
我們想要一些比較來(lái)比較牌的所有屬性,一些比較比較rank?我們?cè)撛鯓油ㄟ^(guò)suit來(lái)排序?此外,相等性的比較必須并行計(jì)算hash。如果我們?cè)趆ash中包含多個(gè)屬性,我們需要將其包含在相等性的比較中。在這種情況下,似乎牌之間的相等和不相等必須全部的Card比較,因?yàn)槲覀兊膆ash包括了rank和suit。
Card之間的比較順序,無(wú)論如何都應(yīng)該只有rank。和整數(shù)的比較同樣也應(yīng)該只有rank。當(dāng)發(fā)現(xiàn)分牌這一特殊情況,hand.cards[0].rank == hand.cards[1].rank會(huì)處理的很好,因?yàn)樵诜峙埔?guī)則中它是顯式的。
2. 同一個(gè)類的對(duì)象的比較實(shí)現(xiàn)我們來(lái)看看一個(gè)簡(jiǎn)單的同一類的比較通過(guò)觀察一個(gè)更完整的BlackJackCard類
class BlackJackCard: def __init__(self, rank, suit, hard, soft): self.rank = rank self.suit = suit self.hard = hard self.soft = soft def __lt__(self, other): if not isinstance( other, BlackJackCard ): return NotImplemented return self.rank < other.rank def __le__(self, other): try: return self.rank <= other.rank except AttributeError: return NotImplemented def __gt__(self, other): if not isinstance(other, BlackJackCard): return NotImplemented return self.rank > other.rank def __ge__(self, other): if not isinstance(other, BlackJackCard): return NotImplemented return self.rank >= other.rank def __eq__(self, other): if not isinstance(other, BlackJackCard): return NotImplemented return self.rank == other.rank and self.suit == other.suit def __ne__(self, other): if not isinstance(other, BlackJackCard): return NotImplemented return self.rank != other.rank and self.suit != other.suit def __str__(self): return "{rank}{suit}".format(**self.__dict__)
現(xiàn)在我們已經(jīng)定義了所有六個(gè)比較運(yùn)算符。
我們已經(jīng)向您展示了兩種類型檢查:顯式和隱式。顯式類型檢查使用isinstance()。隱式類型檢查使用try:塊。使用try:塊有概念上的小優(yōu)勢(shì),它能避免重復(fù)的類名。有可能會(huì)有人想發(fā)明一種變體牌來(lái)兼容BlackJackCard但不是定義為適當(dāng)?shù)淖宇悺J褂?b>isinstance()可以防止一個(gè)無(wú)效類來(lái)保證工作正常。
try:塊會(huì)允許一個(gè)類使用rank屬性。這變成一個(gè)難以解決問(wèn)題的風(fēng)險(xiǎn)會(huì)變?yōu)榱悖鳛轭愒趹?yīng)用程序的其他地方可能會(huì)失敗。同樣,Card實(shí)例與金融建模應(yīng)用程序類比較出現(xiàn)根據(jù)牌值排序的屬性。
在接下來(lái)的例子中,我們將關(guān)注try:塊。isinstance()方法檢查一直是Python慣用方法且應(yīng)用廣泛。我們通過(guò)顯式地返回NotImplemented來(lái)告知Python,這個(gè)操作符并不是用來(lái)實(shí)現(xiàn)這種類型數(shù)據(jù)的。Python可以顛倒參數(shù)順序來(lái)看看另一個(gè)操作數(shù)是否提供了實(shí)現(xiàn)方法。如果沒(méi)有找到有效的操作符,則TypeError異常將被拋出。
我們省略了三個(gè)子類定義和工廠函數(shù),留下card21()作為一個(gè)練習(xí)。
我們也省略了同類的比較,我們將在下一節(jié)看到。通過(guò)這個(gè)類,我們可以成功的比較牌。下面是一個(gè)例子,我們創(chuàng)建并比較三張牌:
>>> two = card21(2, "?") >>> three = card21(3, "?") >>> two_c = card21(2, "?")
根據(jù)這些Cards類,我們可以進(jìn)行一些比較,如下代碼片段所示:
>>> two == two_c False >>> two.rank == two_c.rank True >>> two < three True >>> two_c < three True
定義似乎和預(yù)期的一樣。
3. 混合類對(duì)象的比較實(shí)現(xiàn)我們使用BlackJackCard類為例,當(dāng)我們嘗試比較來(lái)自不同類的兩個(gè)操作數(shù)時(shí),看看會(huì)發(fā)生什么。
下面是Card實(shí)例,我們可以和int值相比較:
>>> two = card21(2, "?") >>> two < 2 Traceback (most recent call last): File "", line 1, in TypeError: unorderable types: Number21Card() < int() >>> two > 2 Traceback (most recent call last): File " ", line 1, in TypeError: unorderable types: Number21Card() > int()
這就是我們期望的,BlackJackCard、Number21Card的子類沒(méi)有提供所需的特殊方法,所以有TypeError異常。
然而,考慮下面的兩個(gè)例子:
>>> two == 2 False >>> two == 3 False
為什么是這樣的結(jié)果?當(dāng)面臨一個(gè)NotImplemented值,Python會(huì)對(duì)調(diào)操作數(shù)。在這種情況下,整數(shù)值定義int.__eq__()方法,容忍一個(gè)意想不到的類對(duì)象。
4. Hard點(diǎn)數(shù)、Soft點(diǎn)數(shù)和多態(tài)性我們定義Hand這樣它將執(zhí)行一些有意義的混合類比較。與其他的比較,我們必須確定這正是我們要比較的。
對(duì)于Hands之間的相等比較,我們應(yīng)該比較所有牌。
對(duì)于Hands比較順序,我們需要比較每個(gè)Hand對(duì)象的一個(gè)屬性。為了逐個(gè)和int相比較,我們應(yīng)該讓Hand對(duì)象的總數(shù)逐個(gè)相比較。為了有一個(gè)總數(shù),在21點(diǎn)游戲中我們必須分類hard點(diǎn)數(shù)和soft點(diǎn)數(shù)。
當(dāng)有一個(gè)A在手,會(huì)有下面兩個(gè)候選點(diǎn)數(shù):
soft點(diǎn)數(shù)把A當(dāng)作11。如果soft點(diǎn)數(shù)超過(guò)21,那么A當(dāng)作1。
hard點(diǎn)數(shù)把A當(dāng)作1。
這意味著手牌的總和不是簡(jiǎn)單的牌的總和。
首先我們必須確定是否有一個(gè)A在手。確定這些,我們可以確定是否有一個(gè)有效的(小于或等于21)的soft點(diǎn)數(shù)。否則,我們將依靠hard點(diǎn)數(shù)。
多態(tài)性的一個(gè)癥狀是依靠isinstance()來(lái)確定子類的成員。一般來(lái)說(shuō),這違反了基本的封裝特性。一組好的多態(tài)的子類定義應(yīng)該完全對(duì)等且?guī)в邢嗤姆椒ê灻@硐肭闆r下,類的定義是不透明的,我們不需要看類的內(nèi)部定義。一組多態(tài)的類使用廣泛的isinstance()檢測(cè)。在某些情況下,isinstance()是必要的。當(dāng)使用一個(gè)內(nèi)置類的時(shí)候都會(huì)出現(xiàn)這樣。我們不能追溯添加方法函數(shù)到內(nèi)置類中,子類化它們來(lái)添加一個(gè)多態(tài)性輔助方法可能是不值得的。
對(duì)于一些特殊的方法,有必要看到isinstance()用于實(shí)現(xiàn)跨多個(gè)類對(duì)象的操作,沒(méi)有簡(jiǎn)單的繼承層次結(jié)構(gòu)。在下一節(jié),與之無(wú)關(guān)的類中,我們將向您展示isinstance()的慣用方法。
對(duì)于我們牌的類層次結(jié)構(gòu),我們想要一個(gè)方法(或?qū)傩?來(lái)標(biāo)識(shí)A,而不是用isinstance()。這是一個(gè)多態(tài)輔助方法。它確保我們可以辨別否則等價(jià)類會(huì)分開。
我們有兩個(gè)選擇:
添加一個(gè)類級(jí)別的屬性
添加一個(gè)方法
因?yàn)楸J氐馁€注方式,我們有兩個(gè)原因去檢查A。如果莊家的牌是A,它會(huì)觸發(fā)一個(gè)保險(xiǎn)的賭注。如果莊家手牌(或玩家的手牌)有一個(gè)A,會(huì)有一個(gè)soft點(diǎn)數(shù)與hard點(diǎn)數(shù)的計(jì)算。
hard點(diǎn)數(shù)和soft點(diǎn)數(shù)是card.soft - card.hard值的差。我們可以在AceCard里面的定義看到這個(gè)值是10。然而,深入類的內(nèi)部可以看到該實(shí)現(xiàn)違背了封裝性。
我們可以將BlackjackCard作為透明的,然后檢查card.soft - card.hard != 0是否為真。如果為真,這些信息足夠算出hard點(diǎn)數(shù)和soft點(diǎn)數(shù)。
下面是一個(gè)使用total方法計(jì)算soft值和hard值之間差值的版本:
def total(self): delta_soft = max(c.soft-c.hard for c in self.cards) hard = sum(c.hard for c in self.cards) if hard+delta_soft <= 21: return hard+delta_soft return hard
我們將計(jì)算hard點(diǎn)數(shù)和soft點(diǎn)數(shù)差作為delta_soft。對(duì)于大多數(shù)牌,差異是零。對(duì)于A,差異是非零。
鑒于hard點(diǎn)數(shù)和delta_soft,我們可以確定返回那個(gè)總數(shù)。如果是hard + delta_soft小于或等于21,值是soft點(diǎn)數(shù)。如果soft點(diǎn)數(shù)大于21,又恢復(fù)到hard點(diǎn)數(shù)。
我們可以考慮讓值21為顯式常量。一個(gè)有意義的名字有時(shí)比文字更有幫助。因?yàn)?1點(diǎn)的規(guī)則,21不太可能會(huì)改變到一個(gè)不同的值。沒(méi)有比文字含義的21更有意義的了。
5. 混合類比較示例為Hand對(duì)象給定一個(gè)點(diǎn)數(shù),我們可以有意義地定義Hand實(shí)例之間的比較以及Hand和int之間的對(duì)比。為了確定我們做哪一種比較,我們被迫使用isinstance()。
以下是部分Hand比較的定義:
class 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__) def __eq__(self, other): if isinstance(other, int): return self.total() == other try: return (self.cards == other.cards and self.dealer_card == other.dealer_card) except AttributeError: return NotImplemented def __lt__(self, other): if isinstance(other, int): return self.total() < other try: return self.total() < other.total() except AttributeError: return NotImplemented def __le__(self, other): if isinstance(other, int): return self.total() <= other try: return self.total() <= other.total() except AttributeError: return NotImplemented __hash__ = None def total(self): delta_soft = max(c.soft-c.hard for c in self.cards) hard = sum(c.hard for c in self.cards) if hard+delta_soft <= 21: return hard+delta_soft return hard
我們定義了三個(gè)比較,不是所有的六個(gè)。
為了與Hand交互我,們需要幾個(gè)Card對(duì)象:
>>> two = card21(2, "?") >>> three = card21(3, "?") >>> two_c = card21(2, "?") >>> ace = card21(1, "?") >>> cards = [ace, two, two_c, three]
我們將使用這個(gè)序列的牌來(lái)看看兩個(gè)不同的hand實(shí)例。
第一個(gè)Hands對(duì)象有一個(gè)無(wú)關(guān)緊要的莊家的Card對(duì)象和先前創(chuàng)建的四張牌。Card對(duì)象中的一個(gè)是A:
>>> h= Hand(card21(10,"?"), *cards) >>> print(h) A?, 2?, 2?, 3? >>> h.total() 18
soft點(diǎn)數(shù)是18,hard點(diǎn)數(shù)是8。
下面是第二個(gè)對(duì)象,有一個(gè)額外的Card對(duì)象:
>>> h2= Hand(card21(10,"?"), card21(5,"?"), *cards) >>> print(h2) 5?, A?, 2?, 2?, 3? >>> h2.total() 13
hard點(diǎn)數(shù)是13。沒(méi)有soft點(diǎn)數(shù),因?yàn)樗^(guò)了21。
Hands之間的比較工作得很好,如下代碼片段所示:
>>> h < h2 False >>> h > h2 True
我們基于比較運(yùn)算符對(duì)Hands進(jìn)行排名。
我們也可以讓Hands與整數(shù)進(jìn)行比較,如下代碼片段所示:
>>> h == 18 True >>> h < 19 True >>> h > 17 Traceback (most recent call last): File "", line 1, in TypeError: unorderable types: Hand() > int()
只要與整數(shù)的比較正常工作,Python不會(huì)被迫撤回。前面的例子告訴我們當(dāng)沒(méi)有__gt__()方法。Python檢查相反的操作數(shù),對(duì)于Hand整數(shù)17也沒(méi)有適當(dāng)?shù)?b>__lt__()方法。
我們可以添加必要的__gt__()和__ge__()函數(shù)使得Hand與整數(shù)正常工作。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/44187.html
摘要:這些基本的特殊方法在類中定義中幾乎總是需要的。和方法對(duì)于一個(gè)對(duì)象,有兩種字符串表示方法。這些都和內(nèi)置函數(shù)以及方法緊密結(jié)合。帶有說(shuō)明符的合理響應(yīng)是返回。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python 有許多特殊方法允許類與Python緊密結(jié)合,標(biāo)準(zhǔn)庫(kù)參考將其稱之為基本,基礎(chǔ)或本質(zhì)可能是更好的術(shù)語(yǔ)。這些特殊...
摘要:有三個(gè)用例通過(guò)和方法定義相等性檢測(cè)和值不可變對(duì)象對(duì)于有些無(wú)狀態(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)用。這兩步的過(guò)程允許引用計(jì)數(shù)或垃圾收集刪除已引用的對(duì)象,讓弱引用懸空。這允許在方法設(shè)置對(duì)象屬性值之前進(jìn)行處理。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python __del__()方法 ...
摘要:第二章與的無(wú)縫集成基本特殊方法筆記中有有一些特殊的方法它們?cè)试S我們的類和更好的集成和方法通常方法表示的對(duì)象對(duì)用戶更加友好這個(gè)方法是有對(duì)象的方法實(shí)現(xiàn)的什么時(shí)候重寫跟非集合對(duì)象一個(gè)不包括其他集合對(duì)象的簡(jiǎn)單對(duì)象這類對(duì)象格式通常不會(huì)特別復(fù) 第二章 與Python的無(wú)縫集成----基本特殊方法.(Mastering Objecting-oriented Python 筆記) python中有有一...
閱讀 887·2023-04-25 19:17
閱讀 2184·2021-09-10 11:26
閱讀 1902·2019-08-30 15:54
閱讀 3416·2019-08-30 15:53
閱讀 2683·2019-08-30 11:20
閱讀 3397·2019-08-29 15:12
閱讀 1235·2019-08-29 13:16
閱讀 2390·2019-08-26 12:19