Python抽象基類(lèi)的定義與使用方法
前言:
我們寫(xiě)Python
基本不需要自己創(chuàng)建抽象基類(lèi),而是通過(guò)鴨子類(lèi)型來(lái)解決大部分問(wèn)題?!读鲿车腜ython》作者使用了15年Python
,但只在項(xiàng)目中創(chuàng)建過(guò)一個(gè)抽象基類(lèi)。我們更多時(shí)候是創(chuàng)建現(xiàn)有抽象基類(lèi)的子類(lèi),或者使用現(xiàn)有的抽象基類(lèi)注冊(cè)。本文的意義在于,了解抽象基類(lèi)的定義與使用,可以幫助我們理解抽象基類(lèi)是如何實(shí)現(xiàn)的,為我們以后學(xué)習(xí)后端語(yǔ)言(比如Java
、Golang
)打下基礎(chǔ)。畢竟抽象基類(lèi)是編程語(yǔ)言通用設(shè)計(jì)。
1、定義抽象基類(lèi)的子類(lèi)
先回顧下什么是抽象基類(lèi):Python
的抽象基類(lèi)是指必須讓繼承它的子類(lèi)去實(shí)現(xiàn)它所要求的抽象方法的類(lèi)。
如下代碼定義了抽象基類(lèi)collections.MutableSequence的子類(lèi):
import collections Card = collections.namedtuple('Card', ['rank', 'suit']) class FrenchDeck2(collections.MutableSequence): ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split() def __init__(self): self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks] def __len__(self): return len(self._cards) def __getitem__(self, position): return self._cards[position] def __setitem__(self, position, value): # <1> self._cards[position] = value def __delitem__(self, position): # <2> del self._cards[position] def insert(self, position, value): # <3> self._cards.insert(position, value)
通過(guò)抽象基類(lèi)collections.MutableSequence
源碼:
可以發(fā)現(xiàn),它有三個(gè)抽象方法__setitem__
、 __delitem__
、insert
,所以FrenchDeck2
類(lèi)必須實(shí)現(xiàn)它們。而對(duì)于其他非抽象方法比如append
、extend
、pop
等,則可以直接繼承無(wú)需實(shí)現(xiàn)。
注意:Python
只會(huì)在運(yùn)行時(shí)實(shí)例化FrenchDeck2
類(lèi)時(shí)真正檢查抽象方法的實(shí)現(xiàn),如果未實(shí)現(xiàn)會(huì)拋出TypeError
異常,提示Can't instantiate abstract class
之類(lèi)的。
2、標(biāo)準(zhǔn)庫(kù)中的抽象基類(lèi)
為了知道哪些抽象基類(lèi)可以使用,我們可以看看標(biāo)準(zhǔn)庫(kù)。
collections.abc
collections.abc
的抽象基類(lèi)如下圖所示:
Iterable、Container、Sized
這三個(gè)抽象基類(lèi)是最基礎(chǔ)的類(lèi),各個(gè)集合都繼承了這三個(gè)抽象基類(lèi)。
Itearble
通過(guò)__iter__
方法支持迭代Container
通過(guò)__contains__
方法支持in運(yùn)算符Sized
通過(guò)__len__
方法支持len()
函數(shù)
Sequence、Mapping、Set
不可變集合類(lèi)型,各自都有可變的子類(lèi)。
MappingView
.items()
、.keys()
、 .values()
返回的對(duì)象分別是ItemsView
、KeysView
和ValuesView
的實(shí)例。
Callable、Hashable
為內(nèi)置函數(shù)isinstance
提供支持,判斷對(duì)象能不能調(diào)用或散列。
Iterator
迭代器。
numbers
numbers
的抽象基類(lèi)有以下幾種:
Number
Complex
Real
Rational
Integral
這叫做數(shù)字塔,頂部是超類(lèi),底部是子類(lèi)。比如使用isinstance
(x, numbers.Integral)檢查一個(gè)數(shù)是不是整數(shù),這樣代碼就能接受int
、bool
(int的子類(lèi)),再比如使用isinstance
(x, numbers.Real)檢查浮點(diǎn)數(shù),這樣代碼就能接受bool
、int
、float
、fractions.Fraction
。
3、定義抽象基類(lèi)
抽象基類(lèi)的示例代碼如下:
# BEGIN TOMBOLA_ABC import abc class Tombola(abc.ABC): # <1> @abc.abstractmethod def load(self, iterable): # <2> """Add items from an iterable.""" @abc.abstractmethod def pick(self): # <3> """Remove item at random, returning it. This method should raise `LookupError` when the instance is empty. """ def loaded(self): # <4> """Return `True` if there's at least 1 item, `False` otherwise.""" return bool(self.inspect()) # <5> def inspect(self): """Return a sorted tuple with the items currently inside.""" items = [] while True: # <6> try: items.append(self.pick()) except LookupError: break self.load(items) # <7> return tuple(sorted(items)) # END TOMBOLA_ABC
要點(diǎn):
- 繼承
abc.ABC
- 使用
@abc.abstractmethod
裝飾器標(biāo)記抽象方法 - 抽象基類(lèi)也可以包含普通方法
- 抽象基類(lèi)的子類(lèi)必須覆蓋抽象方法(普通方法可以不覆蓋),可以使用super()函數(shù)調(diào)用抽象方法,為它添加功能,而不是從頭開(kāi)始實(shí)現(xiàn)
4、再看白鵝類(lèi)型
白鵝類(lèi)型的定義有一點(diǎn)難以理解,如果理解了虛擬子類(lèi),就能加快理解白鵝類(lèi)型。虛擬子類(lèi)并不是抽象基類(lèi)的真正子類(lèi),而是注冊(cè)到抽象基類(lèi)上的子類(lèi),這樣Python
就不會(huì)做強(qiáng)制檢查了。
注冊(cè)的方式有兩種:
- register方法
Python3.3
以前只能使用register方法,比如collections.abc
模塊的源碼中,把內(nèi)置類(lèi)型tuple
、str
、range
和memoryview
注冊(cè)為Sequence
的虛擬子類(lèi):
Sequence.register(tuple) Sequence.register(str) Sequence.register(range) Sequence.register(memoryview)
- register裝飾器
把TomboList
注冊(cè)為Tombola
的虛擬子類(lèi):
@Tombola.register class TomboList(list): ...
白鵝類(lèi)型和鴨子類(lèi)型是Python
的動(dòng)態(tài)特性,它們的共同點(diǎn)是,只要長(zhǎng)的像,Python
就不會(huì)做強(qiáng)制檢查,鴨子類(lèi)型是針對(duì)普通類(lèi)的子類(lèi)而言的,白鵝類(lèi)型是針對(duì)抽象基類(lèi)的虛擬子類(lèi)而言的。
參考資料:
《流暢的Python》第11章 接口:從協(xié)議到抽象基類(lèi)
到此這篇關(guān)于Python抽象基類(lèi)的定義與使用方法的文章就介紹到這了,更多相關(guān)Python抽象基類(lèi)的定義與使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python進(jìn)程間數(shù)據(jù)交互的幾種實(shí)現(xiàn)方式
本文主要介紹了python進(jìn)程數(shù)據(jù)交互的幾種實(shí)現(xiàn)方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05Python中json.dumps()和json.dump()的區(qū)別小結(jié)
在Python中,json.dumps()和json.dump()是兩個(gè)常用的函數(shù),本文主要介紹了Python中json.dumps()和json.dump()的區(qū)別小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02Python基于easygui實(shí)現(xiàn)pdf和word轉(zhuǎn)換小程序
這篇文章主要為大家詳細(xì)介紹了Python如何基于easygui實(shí)現(xiàn)pdf和word轉(zhuǎn)換小程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04pandas?實(shí)現(xiàn)?in?和?not?in?的用法及使用心得
pandas按條件篩選數(shù)據(jù)時(shí),除了使用query()方法,還可以使用isin和對(duì)isin取反進(jìn)行條件篩選,今天通過(guò)本文給大家介紹pandas?實(shí)現(xiàn)?in?和?not?in?的用法及使用心得,感興趣的朋友跟隨小編一起看看吧2023-01-01Python實(shí)現(xiàn)葵花8號(hào)衛(wèi)星數(shù)據(jù)自動(dòng)下載實(shí)例
這篇文章主要為大家介紹了Python實(shí)現(xiàn)葵花8號(hào)衛(wèi)星數(shù)據(jù)自動(dòng)下載實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10關(guān)于tensorflow的幾種參數(shù)初始化方法小結(jié)
今天小編就為大家分享一篇關(guān)于tensorflow的幾種參數(shù)初始化方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01python實(shí)現(xiàn)將中文日期轉(zhuǎn)換為數(shù)字日期
這篇文章主要介紹了python實(shí)現(xiàn)將中文日期轉(zhuǎn)換為數(shù)字日期,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07詳解Python3.8+PyQt5+pyqt5-tools+Pycharm配置詳細(xì)教程
這篇文章主要介紹了Python3.8+PyQt5+pyqt5-tools+Pycharm配置詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-11-11