1. 程式人生 > >Python霧裡看花-抽象類ABC (abstract base class)

Python霧裡看花-抽象類ABC (abstract base class)

首先認識模組 abc,python中沒有提供抽象類與抽象方法,然而提供了內建模組abc來模擬實現抽象類,例如提供泛對映型別的抽象類 abc.MutableMapping

  • 繼承abc.MutableMapping構造一個泛對映型別(類似python中的dict)
# -*- coding: utf-8 -*-
from collections import abc


class MyDic(abc.MutableMapping):

    def __init__(self):
        pass

    def __setitem__
(self, key, value):
print ('key: %s val: %s' % (key, value)) def __delitem__(self, key): print ('key: %s ' % key) def __getitem__(self, item): print ('item: %s ' % str(item)) def __iter__(self): pass def __len__(self): pass
  • 當然繼承abc.Mapping
    也可以,畢竟MutableMapping是其子類

這裡寫圖片描述

  • dict是python中典型的對映型別資料結構,其介面的定義形式也來自abc.Mapping和abc.MutableMapping這倆種抽象類
# -*- coding: utf-8 -*-
from collections import abc


if __name__ == '__main__':
    mydic = dict()
    print( issubclass(dict, abc.MutableMapping))
    print( issubclass(dict, abc.Mapping))
    print( isinstance(mydic, abc.MutableMapping))
    print( isinstance(mydic, abc.Mapping))
  • 執行結果
True
True
True
True

關於abc的通用模組

  • abc.ABCMeta 用來生成抽象基礎類的元類。由它生成的類可以被直接繼承,如下是以註冊的方式使用元類。
# -*- coding: utf-8 -*-
from abc import ABCMeta

"""
生成了一個MyABCDict的抽象基礎類,然後再將dict註冊成它的虛擬子類。
然後通過issubclass或者isinstance都可以判斷出dict確實是出於MyABCDict類
不會出現在類的MRO (Method Resolution Order),因而也不能通過super()來呼叫抽象方法。
沒有實現抽象方法時,例項化時候不會報錯,只有在呼叫時候才會報錯。
"""


class MyABCDict(metaclass=ABCMeta):
    pass


if __name__ == '__main__':

    MyABCDict.register(dict)
    print( issubclass(dict, MyABCDict))
    print( isinstance({}, MyABCDict))
  • abc.ABC輔助類,讓你可以不用關心元類概念,直接繼承它,就有了ABCMeta元類。使用時注意元類衝突
  • @abc.abstractmethod 定義抽象方法,除了這個裝飾器,其餘裝飾器都被deprecated了。

繼承方式使用元類

  • 優點:直接從抽象基類派生子類有一個好處,除非子類實現抽象基類的抽象方法,否則子類不能例項化。
import abc

class PluginBase(metaclass= abc.ABCMeta):
    #__metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def do_something(self, input):
        """Do Some thing."""
        return


class SomePlugin(PluginBase):

    def do_something(self, input):
        print('do_something')

if __name__ == '__main__':
    print ('Subclass:', issubclass(SomePlugin, PluginBase))
    print ('Instance:', isinstance(SomePlugin(), PluginBase))
  • 可以通過 subclasshook方法來實現虛擬方法的檢查