Python中的abc模組
Python中的abc模組
前言
在《抽象基類(ABC)》中,基於C++講述抽象基類。儘管Python設計上以鴨子型別為主,但仍有抽象基類(ABC)的一席之地,它被封裝在了abc模組中供程式設計師使用。
abc模組有以下兩個主要功能:
- 某種情況下,判定某個物件的型別,如:isinstance(a, Sized)
- 強制子類必須實現某些方法,即ABC類的派生類
判斷型別
當我們判斷一個物件是否存在某個方法時,可以使用內建方法hasattr()。
class A(object):
def __len__(self):
pass
if __name__ == "__main__":
a = A()
print("存在__len__方法" if hasattr(a, "__len__") else "沒有__len__方法")
# 輸出:
存在__len__方法
但在Python中,使用hasattr()並非優雅解法,這裡建議isinstance()。
abc模組中定義了Sized類,利用Sized可以判斷一個物件裡是否存在__len__
方法,即:可否對這個物件使用len()函式。
from collections.abc import Sized
class A(object):
def __len__(self):
pass
if __name__ == "__main__":
a = A()
print("存在__len__方法" if isinstance(a, Sized) else "沒有__len__方法")
# 輸出:
存在__len__方法
isinstance實現原理
讓我們看看Sized類的原始碼:
class Sized(metaclass=ABCMeta):
__slots__ = ()
@abstractmethod
def __len__(self):
return 0
@classmethod
def __subclasshook__(cls, C):
if cls is Sized:
return _check_methods(C, "__len__")
return NotImplemented
Sized類改寫了__subclasshook__
魔法方法,使其可以通過isinstance()判斷物件是否含有__len__
方法。同時,這個類必須基於元類abc.ABCMeta。我們也可以依葫蘆畫瓢,實現一個用來判斷物件是否存在greet()函式的類,儘管並不嚴謹:
import abc
class A(metaclass=abc.ABCMeta):
@classmethod
def __subclasscheck__(cls, subclass):
# 存在greet()返回True,不存在返回False
if hasattr(subclass, "greet"):
return True
return False
class B(object):
def greet(self): # 定義了greet()方法
pass
class C(object): # 沒有greet()方法
pass
class D(B): # 繼承自B類,因此繼承了greet()方法
pass
if __name__ == "__main__":
b = B()
c = C()
d = D()
print(isinstance(b, A)) # True
print(isinstance(c, A)) # False
print(isinstance(d, A)) # True
注意,此時A類可以被例項化,因為它還不是抽象基類。
實現ABC類
C++中利用純虛擬函式實現抽象基類,Python中寫法如下:
import abc
class A(metaclass=abc.ABCMeta):
# 利用裝飾器修飾greet()
@abc.abstractmethod
def greet(self):
print("hell world")
if __name__ == "__main__":
a = A()
直譯器如期拋錯:
TypeError: Can't instantiate abstract class A with abstract methods greet
這是因為A類現在就是一個抽象基類了,不可以被例項化,同時,它的子類還必須實現greet()方法,否則例項化子類時直譯器也要報錯:
import abc
class A(metaclass=abc.ABCMeta):
@abc.abstractmethod
def greet(self):
pass
class B(A):
def greet(self):
pass
class C(A):
pass
if __name__ == "__main__":
b = B() # 正常例項化
c = C() # 直譯器拋錯
# 輸出:
# C類中沒有定義greet()方法導致的報錯
Traceback (most recent call last):
File "xxx", line xxx, in <module>
c = C()
TypeError: Can't instantiate abstract class C with abstract methods greet
其他基類
abc模組中還有實現了其他抽象基類,可以用來判斷型別或是繼承方法,這裡不做詳述了:
__all__ = ["Awaitable", "Coroutine",
"AsyncIterable", "AsyncIterator", "AsyncGenerator",
"Hashable", "Iterable", "Iterator", "Generator", "Reversible",
"Sized", "Container", "Callable", "Collection",
"Set", "MutableSet",
"Mapping", "MutableMapping",
"MappingView", "KeysView", "ItemsView", "ValuesView",
"Sequence", "MutableSequence",
"ByteString",
]
檔案所在路徑:…lib\_collocetions_abc.py
總結
-
abc模組中定義的類兼顧了繼承抽象基類與鴨子型別的設計方式。你既可以通過繼承Sized來擁有
__len__
方法,此時instance(物件, Sized)
返回True;也可以在自己設計的類中實現__len__
,instance(物件, Sized)
仍然返回True。 -
對抽象基類來說,需要用到裝飾器 @abc.abstractmethod;對於鴨子型別來說,需要重寫
__subclasshook__
魔法方法。 -
以上都是基於元類abc.ABCMeta實現的。順便提醒,注意
import abc
與from collections import abc
各自的區別。
相關文章
- python中的chardet模組Python
- Python中模組的使用Python
- Python 中argparse模組的使用Python
- Python中paramiko 模組的用法Python
- Python中operator 模組的用法Python
- Python中pathlib 模組的用法Python
- Python中itertools 模組的用法Python
- python中重要的模組--asyncioPython
- Python中模組是什麼?Python有哪些模組?Python
- Python中os模組Python
- Python中的collections.Counter模組Python
- Python中yaml模組的使用教程PythonYAML
- Python中的mechanize模組是什麼?Python
- python中的itertools模組簡單使用Python
- python 模組:itsdangerous 模組Python
- Python模組:time模組Python
- Python中os.walk()模組Python
- Python模組之urllib模組Python
- python模組之collections模組Python
- python的logging模組Python
- python的os模組Python
- Python的shutil模組Python
- Python中的包模組引用成員的方法Python
- Python 模組Python
- [Python模組學習] glob模組Python
- python中的複製copy模組怎麼使用?Python
- Python中爬蟲框架或模組的區別!Python爬蟲框架
- Python中爬蟲框架或模組的區別Python爬蟲框架
- python中re模組的使用(正規表示式)Python
- Python logging模組的使用Python
- python中numpy模組下的np.clip()的用法Python
- 『無為則無心』Python函式 — 36、Python中的模組Python函式
- Python Execl模組Python
- Python mongoHelper模組PythonGo
- Python——JSON 模組PythonJSON
- [Python] pipe模組Python
- Python - 模組包Python
- python——typing模組Python