摘要:第一是在對(duì)象生命周期中初始化是最重要的一步每個(gè)對(duì)象必須正確初始化后才能正常工作。第二是參數(shù)值可以有多種形式。基類對(duì)象的方法對(duì)象生命周期的基礎(chǔ)是它的創(chuàng)建初始化和銷毀。在某些情況下,這種默認(rèn)行為是可以接受的。
注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python
__init__()方法意義重大的原因有兩個(gè)。第一是在對(duì)象生命周期中初始化是最重要的一步;每個(gè)對(duì)象必須正確初始化后才能正常工作。第二是__init__()參數(shù)值可以有多種形式。
因?yàn)橛泻芏喾N方式為__init__()提供參數(shù)值,所以對(duì)于對(duì)象創(chuàng)建有大量的使用案例,我們可以看看其中的幾個(gè)。我們想盡可能的弄清楚,因此我們需要定義一個(gè)初始化來(lái)正確的描述問題域。
在我們接觸__init__()方法之前,無(wú)論如何,我們都需要簡(jiǎn)單粗略地看看Python中隱含的object類的層次結(jié)構(gòu)。
在這一章,我們看看不同形式的簡(jiǎn)單對(duì)象的初始化(例如:打牌)。在這之后,我們還可以看看更復(fù)雜的對(duì)象,就像包含集合的hands以及包含策略和狀態(tài)的players。
隱式超類——object每一個(gè)Python類都隱含了一個(gè)超類:object。它是一個(gè)非常簡(jiǎn)單的類定義,幾乎不做任何事情。我們可以創(chuàng)建object的實(shí)例,但是我們不能用它做太多,因?yàn)樵S多特殊的方法容易拋出異常。
當(dāng)我們自定義一個(gè)類,object則為超類。下面是一個(gè)類定義示例,它使用新的名稱簡(jiǎn)單的繼承了object:
class X: pass
下面是和自定義類的一些交互:
>>> X.__class__>>> X.__class__.__base__
我們可以看到該類是type類的一個(gè)對(duì)象,且它的基類為object。
就像在每個(gè)方法中看到的那樣,我們也看看從object繼承的默認(rèn)行為。在某些情況下,超類的特殊方法是我們想要的。而在其他情況下,我們又需要覆蓋這個(gè)特殊方法。
基類對(duì)象的__init__()方法對(duì)象生命周期的基礎(chǔ)是它的創(chuàng)建、初始化和銷毀。我們將創(chuàng)建和銷毀推遲到后面章節(jié)的高級(jí)特殊方法中講,目前只關(guān)注初始化。
所有類的超類object,有一個(gè)默認(rèn)包含pass的__init__()方法,我們不需要去實(shí)現(xiàn)它。如果不實(shí)現(xiàn)它,則在對(duì)象創(chuàng)建后就不會(huì)創(chuàng)建實(shí)例變量。在某些情況下,這種默認(rèn)行為是可以接受的。
我們總是給對(duì)象添加屬性,該對(duì)象為基類object的子類。思考下面的類,它需要兩個(gè)實(shí)例變量但不初始化它們:
class Rectangle: def area(self): return self.length * self.width
Rectangle類有一個(gè)使用兩個(gè)屬性來(lái)返回一個(gè)值的方法。這些屬性沒有初始化,是合法的Python代碼。它可以明確地避免設(shè)置屬性,雖然感覺有點(diǎn)奇怪,但是合法。
下面是與Rectangle類的交互:
>>> r = Rectangle() >>> r.length, r.width = 13, 8 >>> r.area() 104
顯然這是合法的,但這也是容易混淆的根源,所以也是我們需要避免的原因。
無(wú)論如何,這個(gè)設(shè)計(jì)給予了很大的靈活性,這樣有時(shí)候我們不用在__init__()方法中設(shè)置所有屬性。至此我們走的很順利。一個(gè)可選屬性其實(shí)就是一個(gè)子類,只是沒有真正的正式聲明為子類。我們創(chuàng)建多態(tài)在某種程度上可能會(huì)引起混亂,以及if語(yǔ)句的不恰當(dāng)使用所造成的盤繞。雖然未初始化的屬性可能是有用的,但也很有可能是糟糕設(shè)計(jì)的前兆。
《Python之禪》中的建議:
"顯式比隱式更好。"
一個(gè)__init__()方法應(yīng)該讓實(shí)例變量顯式。
非常差的多態(tài)
靈活和愚蠢就在一念之間。
當(dāng)我們覺得需要像下面這樣寫的時(shí)候,我們正從靈活的邊緣走向愚蠢:
if "x" in self.__dict__:
或者:
try: self.x except AttributeError:
是時(shí)候重新考慮API并添加一個(gè)通用的方法或?qū)傩?。重?gòu)比添加if語(yǔ)句更明智。
在超類中實(shí)現(xiàn)__init__()我們通過實(shí)現(xiàn)__init__()方法來(lái)初始化對(duì)象。當(dāng)一個(gè)對(duì)象被創(chuàng)建,Python首先創(chuàng)建一個(gè)空對(duì)象并為該新對(duì)象調(diào)用__init__()方法。這個(gè)方法函數(shù)通常用來(lái)創(chuàng)建對(duì)象的實(shí)例變量并執(zhí)行任何其他一次性處理。
下面是Card類示例定義的層次結(jié)構(gòu)。我們將定義Card超類和三個(gè)子類,這三個(gè)子類是Card的變種。兩個(gè)實(shí)例變量直接由參數(shù)值設(shè)置,并通過初始化方法計(jì)算:
class Card: 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) class AceCard(Card): def _points(self): return 1, 11 class FaceCard(Card): def _points(self): return 10, 10
在這個(gè)示例中,我們提取__init__()方法到超類,這樣在Card超類中的通用初始化可以適用于三個(gè)子類NumberCard、AceCard和FaceCard。
這是一種常見的多態(tài)設(shè)計(jì)。每一個(gè)子類都提供一個(gè)唯一的_points()方法實(shí)現(xiàn)。所有子類都有相同的簽名:有相同的方法和屬性。這三個(gè)子類的對(duì)象在一個(gè)應(yīng)用程序中可以交替使用。
如果我們?yōu)榛ㄉ褂煤?jiǎn)單的字符,我們可以創(chuàng)建Card實(shí)例,如下所示:
cards = [AceCard("A", "?"), NumberCard("2","?"), NumberCard("3","?"),]
我們?cè)诹斜碇忻杜e出一些牌的類、牌值和花色。從長(zhǎng)遠(yuǎn)來(lái)說(shuō),我們需要更智能的工廠函數(shù)來(lái)創(chuàng)建Card實(shí)例,用這個(gè)方法枚舉52張牌無(wú)聊且容易出錯(cuò)。在我們接觸工廠函數(shù)之前,我們看一些其他問題。
使用__init__()創(chuàng)建顯而易見的常量可以給牌定義花色類。在二十一點(diǎn)中,花色無(wú)關(guān)緊要,簡(jiǎn)單的字符串就可以。
我們使用花色構(gòu)造函數(shù)作為創(chuàng)建常量對(duì)象示例。在許多情況下,我們應(yīng)用中小部分對(duì)象可以通過常量集合來(lái)定義。小部分的靜態(tài)對(duì)象可能是實(shí)現(xiàn)策略模式或狀態(tài)模式的一部分。
在某些情況下,我們會(huì)有一個(gè)在初始化或配置文件中創(chuàng)建的常量對(duì)象池,或者我們可以基于命令行參數(shù)創(chuàng)建常量對(duì)象。我們會(huì)在第十六章《命令行處理》中獲取初始化設(shè)計(jì)和啟動(dòng)設(shè)計(jì)的詳細(xì)信息。
Python沒有簡(jiǎn)單正式的機(jī)制來(lái)定義一個(gè)不可變對(duì)象,我們將在第三章《屬性訪問、特性和描述符》中看看保證不可變性的相關(guān)技術(shù)。在本示例中,花色不可變是有道理的。
下面這個(gè)類,我們將用于創(chuàng)建四個(gè)顯而易見的常量:
class Suit: def __init__(self, name, symbol): self.name = name self.symbol = symbol
下面是通過這個(gè)類創(chuàng)建的常量:
Club, Diamond, Heart, Spade = Suit("Club","?"), Suit("Diamond","?"), Suit("Heart","?"), Suit("Spade","?")
現(xiàn)在我們可以通過下面展示的代碼片段創(chuàng)建cards:
cards = [AceCard("A", Spade), NumberCard("2", Spade), NumberCard("3", Spade),]
這個(gè)小示例的方法對(duì)于單個(gè)字符花色的代碼來(lái)說(shuō)并沒有多大改進(jìn)。在更復(fù)雜的情況下,會(huì)通過這個(gè)方式創(chuàng)建一些策略或狀態(tài)對(duì)象。從小的靜態(tài)常量池中復(fù)用對(duì)象使得策略或狀態(tài)設(shè)計(jì)模式效率更高。
我們必須承認(rèn),在Python中這些對(duì)象并不是技術(shù)上一成不變的,它是可變的。進(jìn)行額外的編碼使得這些對(duì)象真正不可變可能會(huì)有一些好處。
無(wú)關(guān)緊要的不變性
不變性很有吸引力但卻容易帶來(lái)麻煩。有時(shí)候神話般的“惡意程序員”在他們的應(yīng)用程序中通過修改常量值進(jìn)行調(diào)整。從設(shè)計(jì)上考慮,這是非常愚蠢的。這些神話般的、惡意的程序員不會(huì)停止這樣做。在Python中沒有更好的方法保證沒有白癡的代碼。惡意程序員訪問到源碼并且修改它僅僅是希望盡可能輕松地編寫代碼來(lái)修改一個(gè)常數(shù)。
在定義不可變對(duì)象的類的時(shí)候最好不要掙扎太久。在第三章《屬性訪問、特性和描述符》中,我們將在有bug的程序中提供合適的診斷信息來(lái)展示如何實(shí)現(xiàn)不變性。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/37510.html
摘要:簡(jiǎn)單復(fù)合對(duì)象復(fù)合對(duì)象也可被稱為容器。它難以序列化對(duì)象并像這樣初始化來(lái)重建。接口仍然會(huì)導(dǎo)致多種方法計(jì)算。還要注意一些不完全遵循點(diǎn)規(guī)則的方法功能。逐步增加項(xiàng)目的方法和一步加載所有項(xiàng)目的方法是一樣的。另一個(gè)方法就是之前那樣的類定義。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python 在各個(gè)子類中實(shí)現(xiàn)__init_...
摘要:工廠類的函數(shù)就是包裝一些目標(biāo)類層次結(jié)構(gòu)和復(fù)雜對(duì)象的構(gòu)造。連貫的工廠類接口在某些情況下,我們?cè)O(shè)計(jì)的類在方法使用上定義好了順序,按順序求方法的值很像函數(shù)。這個(gè)工廠類可以像下面這樣使用首先,我們創(chuàng)建一個(gè)工廠實(shí)例,然后我們使用那個(gè)實(shí)例創(chuàng)建實(shí)例。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python 通過工廠函數(shù)對(duì) __init_...
摘要:同時(shí),有多個(gè)類級(jí)別的靜態(tài)構(gòu)造函數(shù)的方法。這個(gè)累贅,無(wú)論如何,是被傳遞到每個(gè)單獨(dú)的對(duì)象構(gòu)造函數(shù)表達(dá)式中。我們可能只有幾個(gè)特定的擔(dān)憂,提供額外關(guān)鍵字參數(shù)給構(gòu)造函數(shù)。 注:原書作者 Steven F. Lott,原書名為 Mastering Object-oriented Python 沒有__init__()的無(wú)狀態(tài)對(duì)象 下面這個(gè)示例,是一個(gè)簡(jiǎn)化去掉了__init__()的類。這是一個(gè)常見...
摘要:提議以下的新的生成器語(yǔ)法將被允許在生成器的內(nèi)部使用其中表達(dá)式作用于可迭代對(duì)象,從迭代器中提取元素。子迭代器而非生成器的語(yǔ)義被選擇成為生成器案例的合理泛化。建議如果關(guān)閉一個(gè)子迭代器時(shí),引發(fā)了帶返回值的異常,則將該值從調(diào)用中返回給委托生成器。 導(dǎo)語(yǔ): PEP(Python增強(qiáng)提案)幾乎是 Python 社區(qū)中最重要的文檔,它們提供了公告信息、指導(dǎo)流程、新功能的設(shè)計(jì)及使用說(shuō)明等內(nèi)容。對(duì)于學(xué)習(xí)...
閱讀 1654·2019-08-30 13:18
閱讀 1637·2019-08-29 12:19
閱讀 2188·2019-08-26 13:57
閱讀 4212·2019-08-26 13:22
閱讀 1267·2019-08-26 10:35
閱讀 3051·2019-08-23 18:09
閱讀 2597·2019-08-23 17:19
閱讀 747·2019-08-23 17:18