作者:麥?zhǔn)?/p> 來(lái)源:麥?zhǔn)寰幊?/p> ABC是什么我們來(lái)聊一個(gè)Python進(jìn)階話(huà)題,抽象基類(lèi),,英文是Abstract Base Class,,簡(jiǎn)稱(chēng)為ABC。 這個(gè)名字看起來(lái)很簡(jiǎn)單,,ABC,,但其實(shí)是Python進(jìn)階的重要知識(shí)點(diǎn)。提高Python設(shè)計(jì)能力的重要武器,! 雖然Python相對(duì)Java等相對(duì)比較靈活,。但要設(shè)計(jì)稍微復(fù)雜點(diǎn)的系統(tǒng),高水平的設(shè)計(jì)者還是會(huì)使用一些設(shè)計(jì)技巧,,比如使用ABC,。至少Python內(nèi)置集合類(lèi)就大量使用了ABC。 簡(jiǎn)單來(lái)說(shuō),,ABC是一種抽象的類(lèi),,它只是規(guī)定了一些規(guī)范。要實(shí)現(xiàn)這個(gè)ABC的子類(lèi)必須提供規(guī)范中要求的方法和屬性,。 我們來(lái)看例子吧,。 設(shè)計(jì)場(chǎng)景假設(shè)我們要開(kāi)發(fā)一個(gè)媒體播放器。它可以播放不同的媒體格式,。 在這種情況下,,一個(gè)很好的選擇就是創(chuàng)建一個(gè)ABC來(lái)聲明子類(lèi)需要提供的方法和屬性。 一般的設(shè)計(jì)是這樣的,,讓多個(gè)類(lèi)都實(shí)現(xiàn)一個(gè)通用的函數(shù),,比如 play()。我們將媒體播放器定義為抽象類(lèi),。每種特定的媒體文件格式(如mp4,,MOV,AVI等)都可以提供抽象類(lèi)的具體實(shí)現(xiàn),。 抽象類(lèi)下面是一個(gè)抽象類(lèi),,它需要子類(lèi)提供具體的方法實(shí)現(xiàn)和屬性: class MediaLoader(abc.ABC): @abc.abstractmethod def play(self) -> None: ... @property @abc.abstractmethod def ext(self) -> str: ... abc.ABC是一個(gè)用于控制實(shí)體類(lèi)創(chuàng)建的元類(lèi),。Python的默認(rèn)元類(lèi)是type。默認(rèn)的元類(lèi)當(dāng)創(chuàng)建實(shí)例的時(shí)候不會(huì)檢查抽象方法,。abc.ABC擴(kuò)展了type,,它會(huì)阻止我們?yōu)闆](méi)有被完全實(shí)現(xiàn)的類(lèi)創(chuàng)建實(shí)例。 抽象方法抽象類(lèi)中有兩處使用了裝飾器,。一處使用@abc.abstractmethod ,,另一處同時(shí)使用了@property和@abc.abstractmethod。Python廣泛使用裝飾器來(lái)修改函數(shù)或方法的功能,。在這個(gè)例子中,,它為元類(lèi)ABC提供了額外的細(xì)節(jié)。因?yàn)槲覀儤?biāo)注了某個(gè)方法或?qū)傩允浅橄蟮?,子?lèi)必須實(shí)現(xiàn)相應(yīng)的方法或?qū)傩圆拍艹蔀橛杏玫?、可以被?shí)例化的類(lèi)。 抽象類(lèi)的方法體是**...**,。這個(gè)三點(diǎn)標(biāo)記,,即省略號(hào),確實(shí)是合法的Python 代碼,,用以提醒我們:具體的子類(lèi)需要實(shí)現(xiàn)相應(yīng)的方法,。 抽象屬性我們?cè)趀xt()方法上也使用了@property裝飾器。我們的目的是為了提供一個(gè)名為ext的字符串類(lèi)型的類(lèi)變量,。使用@property把它聲明為屬性,,這樣子類(lèi)可以選擇使用簡(jiǎn)單的變量或者使用方法來(lái)實(shí)現(xiàn)這個(gè)屬性。在實(shí)體類(lèi)中使用簡(jiǎn)單變量可以滿(mǎn)足抽象類(lèi)的要求,,也能通過(guò)mypy的類(lèi)型檢查,。如果需要一些更復(fù)雜的計(jì)算,可以使用方法來(lái)替代簡(jiǎn)單的屬性變量,。 使用了這些標(biāo)記的類(lèi)會(huì)擁有了一個(gè)特殊的屬性__abstractmethods__,。這個(gè)屬性會(huì)列出所有的抽象方法或?qū)傩裕?/p>
測(cè)試一下如果實(shí)現(xiàn)一個(gè)子類(lèi),會(huì)發(fā)生什么,?我們看兩個(gè)例子,,一個(gè)反面例子Wav,它沒(méi)有為抽象提供必要的實(shí)現(xiàn),。一個(gè)正面例子,,它為抽象提供了具體實(shí)現(xiàn)。 >>> class Wav(MediaLoader): ... pass...>>> x = Wav() Traceback (most recent call last): File '<stdin>', line 1, in <module> TypeError: Can't instantiate abstract class Wav with abstract methods ext, play >>> class Ogg(MediaLoader): ... ext = '.ogg' ... def play(self): ... pass...>>> o = Ogg() 子類(lèi)Wav沒(méi)有實(shí)現(xiàn)任何抽象方法,。當(dāng)我們嘗試創(chuàng)建一個(gè)Wav類(lèi)的實(shí)例時(shí),,拋出了異常。因?yàn)樽鳛镸ediaLoader的子類(lèi),,它沒(méi)有實(shí)現(xiàn)ABC要求的規(guī)范,,不能創(chuàng)建實(shí)例,。 而子類(lèi)Ogg提供了抽象屬性的實(shí)現(xiàn),所以它可以被實(shí)例化,。 在創(chuàng)建復(fù)雜的應(yīng)用時(shí),,這有明顯的優(yōu)勢(shì)。像這樣使用抽象類(lèi),,可以確保子類(lèi)符合規(guī)范,,也可以讓mypy很清楚地判斷一個(gè)類(lèi)是否實(shí)現(xiàn)了必要的方法和屬性,在開(kāi)發(fā)過(guò)程中為我們實(shí)時(shí)指出問(wèn)題,。 ABC你懂了嗎,?好啦,,今天就聊到這里,。如果喜歡,記得點(diǎn)贊,! CDA數(shù)據(jù)分析師分享案例,,歡迎大家留言分享你的建議。 |
|