1. 程式人生 > >python 抽象基類

python 抽象基類

具體化抽象基類的兩種方式:

1、通過抽象基類 ABCMeta 的 register 方法註冊。

2、通過繼承的方式。

class Base(metaclass = ABCMeta):
	@classmethod
	def __subclasshook__(cls, subclass):
		if cls is Base:
			return True
		return NotImplemented

class Derive(Base):
	pass
print(issubclass(int, Base))  #True
print(issubclass(int, Derive))  #False

issubclass 放回會呼叫 __subclasscheck__,isinstance 會呼叫 __instancecheck__.

issubclass(int, Base) 呼叫 Base.__subclasscheck__(int) 方法。Base.__subclasscheck__ 方法來自 ABCMate 元類。

呼叫 ABCMate 的 __subclasscheck__ 方法,ABCMate 的 __subclasscheck__ 放回會呼叫 __subclasshook__ 方法。

    def __subclasscheck__(cls, subclass):
        """Override for issubclass(subclass, cls)."""
        # Check cache
        if subclass in cls._abc_cache:
            return True
        # Check negative cache; may have to invalidate
        if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
            # Invalidate the negative cache
            cls._abc_negative_cache = WeakSet()
            cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
        elif subclass in cls._abc_negative_cache:
            return False
        # Check the subclass hook
        ok = cls.__subclasshook__(subclass)   #check 方法呼叫 hook
        if ok is not NotImplemented:
            assert isinstance(ok, bool)
            if ok:
                cls._abc_cache.add(subclass)
            else:
                cls._abc_negative_cache.add(subclass)
            return ok

if cls is Base: 確保了只有 Base 類自己呼叫該方法時,走這一分支;如果是 Base 類的派生類呼叫,則走下一分支,返回 NotImplemented  走預設實現。

__subclasscheck__ 檢查一個類是否是另外一個類的子類,所以只能用在元類上。

issubclass(MySubCls, MyCls)
#等價於 MyCls.__subclasscheck(MySubCls)

抽象基類的用處:
1、繼承自抽象基類,必須實現抽象基類的所有 abstractmethod ,這樣在物件建立階段就會檢查,而不用等到呼叫方法時。
2、將 ducktype 的檢測(是否擁有某方法)統一到 issubclass 和 isinstance 上。
如果正確的實現了介面,便是子類,而不用通過繼承的方式。

hasattr(x, '__iter__') 替換成 isinstance(x, collections.Iterable)