偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Python抽象基類(lèi)的定義與使用

開(kāi)發(fā) 后端
我們寫(xiě)Python基本不需要自己創(chuàng)建抽象基類(lèi),而是通過(guò)鴨子類(lèi)型來(lái)解決大部分問(wèn)題。《流暢的Python》作者使用了15年P(guān)ython,但只在項(xiàng)目中創(chuàng)建過(guò)一個(gè)抽象基類(lèi)。

[[429320]]

我們寫(xiě)Python基本不需要自己創(chuàng)建抽象基類(lèi),而是通過(guò)鴨子類(lèi)型來(lái)解決大部分問(wèn)題?!读鲿车腜ython》作者使用了15年P(guān)ython,但只在項(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ì)。

定義抽象基類(lèi)的子類(lèi)

先回顧下什么是抽象基類(lèi):Python的抽象基類(lèi)是指必須讓繼承它的子類(lèi)去實(shí)現(xiàn)它所要求的抽象方法的類(lèi)。如下代碼定義了抽象基類(lèi)collections.MutableSequence的子類(lèi):

  1. import collections 
  2.  
  3. Card = collections.namedtuple('Card', ['rank''suit']) 
  4.  
  5. class FrenchDeck2(collections.MutableSequence): 
  6.     ranks = [str(n) for n in range(2, 11)] + list('JQKA'
  7.     suits = 'spades diamonds clubs hearts'.split() 
  8.  
  9.     def __init__(self): 
  10.         self._cards = [Card(rank, suit) for suit in self.suits 
  11.                                         for rank in self.ranks] 
  12.  
  13.     def __len__(self): 
  14.         return len(self._cards) 
  15.  
  16.     def __getitem__(self, position): 
  17.         return self._cards[position] 
  18.  
  19.     def __setitem__(self, position, value):  # <1> 
  20.         self._cards[position] = value 
  21.  
  22.     def __delitem__(self, position):  # <2> 
  23.         del self._cards[position] 
  24.  
  25.     def insert(self, position, value):  # <3> 
  26.         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)的。

標(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。

定義抽象基類(lèi)

本小結(jié)可以跳過(guò)。不過(guò)了解抽象基類(lèi)的定義有助于閱讀標(biāo)準(zhǔn)庫(kù)和其他包中的抽象基類(lèi)源碼。

抽象基類(lèi)的示例代碼如下:

  1. BEGIN TOMBOLA_ABC 
  2.  
  3. import abc 
  4.  
  5. class Tombola(abc.ABC):  # <1> 
  6.  
  7.     @abc.abstractmethod 
  8.     def load(self, iterable):  # <2> 
  9.         """Add items from an iterable.""" 
  10.  
  11.     @abc.abstractmethod 
  12.     def pick(self):  # <3> 
  13.         """Remove item at random, returning it. 
  14.         This method should raise `LookupError` when the instance is empty. 
  15.         ""
  16.  
  17.     def loaded(self):  # <4> 
  18.         """Return `True` if there's at least 1 item, `False` otherwise.""" 
  19.         return bool(self.inspect())  # <5> 
  20.  
  21.  
  22.     def inspect(self): 
  23.         """Return a sorted tuple with the items currently inside.""" 
  24.         items = [] 
  25.         while True:  # <6> 
  26.             try: 
  27.                 items.append(self.pick()) 
  28.             except LookupError: 
  29.                 break 
  30.         self.load(items)  # <7> 
  31.         return tuple(sorted(items)) 
  32.  
  33.  
  34. END TOMBOLA_ABC 

要點(diǎn):

  1. 繼承abc.ABC
  2. 使用@abc.abstractmethod裝飾器標(biāo)記抽象方法
  3. 抽象基類(lèi)也可以包含普通方法
  4. 抽象基類(lèi)的子類(lèi)必須覆蓋抽象方法(普通方法可以不覆蓋),可以使用super()函數(shù)調(diào)用抽象方法,為它添加功能,而不是從頭開(kāi)始實(shí)現(xiàn)

再看白鵝類(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):

  1. Sequence.register(tuple) 
  2. Sequence.register(str) 
  3. Sequence.register(range) 
  4. Sequence.register(memoryview) 

register裝飾器

把TomboList注冊(cè)為T(mén)ombola的虛擬子類(lèi):

  1. @Tombola.register 
  2. class TomboList(list): 
  3.     ... 

白鵝類(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)

 

責(zé)任編輯:武曉燕 來(lái)源: dongfanger
相關(guān)推薦

2024-12-25 08:00:44

Python抽象基類(lèi)JSON

2009-07-28 17:38:02

ASP.NET多態(tài)抽象基類(lèi)

2025-02-07 08:47:38

C#派生類(lèi)接口

2009-12-21 16:24:24

WCF新到工廠

2023-12-08 14:50:45

Python枚舉類(lèi)工具

2009-08-03 18:12:31

C#抽象類(lèi)

2010-07-06 08:58:52

UML圖表達(dá)C++

2009-08-14 15:54:17

C#接口和抽象類(lèi)

2009-08-04 17:42:23

DataSourceCASP.NET

2011-06-28 10:55:20

C#接口抽象類(lèi)

2010-01-27 10:22:53

C++基類(lèi)

2010-01-21 13:33:44

C++基類(lèi)

2011-10-25 09:52:56

jQuery

2022-05-11 15:06:02

MySQL游標(biāo)SQL

2009-07-22 18:08:00

ASP.NET基類(lèi)

2015-09-08 11:06:46

設(shè)計(jì)編輯窗體

2009-07-14 13:49:29

原型

2009-06-29 15:15:00

抽象類(lèi)Java

2009-12-02 14:55:46

PHP抽象類(lèi)abstr

2012-02-29 09:32:01

Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)