抽象基類的核心定義在abc模塊中,模塊中包括了建立抽象基類須要的修飾符和元類型
abc.ABCMeta
app用來生成抽象基礎類的元類。由它生成的類能夠被直接繼承。
abc.ABC
ssh輔助類,讓你能夠不用關心元類概念,直接繼承它,就有了ABCMeta元類。使用時注意元類衝突
@abc.abstractmethod
ide定義抽象方法,除了這個裝飾器,其他裝飾器都被deprecated了ui
from abc import ABCMeta,abstractmethod class Animal(metaclass = ABCMeta): test = "hello world" def __init__(self): self.food = None @abstractmethod def eat(self): pass @abstractmethod def run(self): pass @classmethod def __subclasshook__(cls, subclass): #重寫__subclasshook__方法,判斷是否爲子類 print ("come in") if cls is Animal: if any("eat" in b.__dict__ for b in subclass.__mro__): return True return NotImplemented
以上爲Animal的抽象基類,注意重寫了__subclasscheck__(cls, subclass)方法來改變issubclass或者isinstance的行爲,__subclasscheck__(cls, subclass)必須爲@classmethodthis
具體化抽象類能夠有兩種方式,一種經過註冊(register),另一種經過繼承。spa
class Monkey: def __init__(self):
#不會出如今類的__mro__,因此不會經過super()方法調用基類方法 super().__init__() self.food= "banana" def eat(self): print ("{0} eat {1}".format(self.__class__.__name__, self.food))
#沒有實現抽象方法時,實例化的時候不會報錯,只有在調用的時候纔會報錯 #def run(self): #pass if __name__ == "__main__": Animal.register(Monkey)
print (issubclass(Animal,Monkey))
m = Monkey()
m.eat()
>>>> come in
>>>> True
>>>> Monkey eat banana
>>>> (<class '__main__.Monkey'>, <class 'object'>)code
註冊方式的缺點:不會出如今類的MRO
(Method Resolution Order),故而也不能經過super()
來調用抽象方法。當沒有實現抽象方法時,實例化時候不會報錯,只有在調用時候纔會報錯。
直接從抽象基類派生子類有一個好處,除非子類實現抽象基類的抽象方法,不然子類不能實例化。 orm
class Monkey(Animal): def __init__(self): super().__init__() self.food= "banana" def eat(self): print ("{0} eat {1}".format(self.__class__.__name__, self.food)) def run(self): pass if __name__ == "__main__": Animal.register(Monkey) print (issubclass(Animal,Monkey))) m = Monkey() m.eat() print (Monkey.__mro__)
class ABCMeta(type): """Metaclass for defining Abstract Base Classes (ABCs). Use this metaclass to create an ABC. An ABC can be subclassed directly, and then acts as a mix-in class. You can also register unrelated concrete classes (even built-in classes) and unrelated ABCs as 'virtual subclasses' -- these and their descendants will be considered subclasses of the registering ABC by the built-in issubclass() function, but the registering ABC won't show up in their MRO (Method Resolution Order) nor will method implementations defined by the registering ABC be callable (not even via super()). """ # A global counter that is incremented each time a class is # registered as a virtual subclass of anything. It forces the # negative cache to be cleared before its next use. # Note: this counter is private. Use `abc.get_cache_token()` for # external code. _abc_invalidation_counter = 0 def __new__(mcls, name, bases, namespace): cls = super().__new__(mcls, name, bases, namespace) # Compute set of abstract method names abstracts = {name for name, value in namespace.items() if getattr(value, "__isabstractmethod__", False)} for base in bases: for name in getattr(base, "__abstractmethods__", set()): value = getattr(cls, name, None) if getattr(value, "__isabstractmethod__", False): abstracts.add(name) cls.__abstractmethods__ = frozenset(abstracts) # Set up inheritance registry cls._abc_registry = WeakSet() cls._abc_cache = WeakSet() cls._abc_negative_cache = WeakSet() cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter return cls def register(cls, subclass): """Register a virtual subclass of an ABC. Returns the subclass, to allow usage as a class decorator. """ if not isinstance(subclass, type): raise TypeError("Can only register classes") if issubclass(subclass, cls): return subclass # Already a subclass # Subtle: test for cycles *after* testing for "already a subclass"; # this means we allow X.register(X) and interpret it as a no-op. if issubclass(cls, subclass): # This would create a cycle, which is bad for the algorithm below raise RuntimeError("Refusing to create an inheritance cycle") cls._abc_registry.add(subclass) ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache return subclass def _dump_registry(cls, file=None): """Debug helper to print the ABC registry.""" print("Class: %s.%s" % (cls.__module__, cls.__qualname__), file=file) print("Inv.counter: %s" % ABCMeta._abc_invalidation_counter, file=file) for name in sorted(cls.__dict__.keys()): if name.startswith("_abc_"): value = getattr(cls, name) print("%s: %r" % (name, value), file=file) def __instancecheck__(cls, instance): """Override for isinstance(instance, cls).""" # Inline the cache checking subclass = instance.__class__ if subclass in cls._abc_cache: return True subtype = type(instance) if subtype is subclass: if (cls._abc_negative_cache_version == ABCMeta._abc_invalidation_counter and subclass in cls._abc_negative_cache): return False # Fall back to the subclass check. return cls.__subclasscheck__(subclass) return any(cls.__subclasscheck__(c) for c in {subclass, subtype}) 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) 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 # Check if it's a direct subclass if cls in getattr(subclass, '__mro__', ()): cls._abc_cache.add(subclass) return True # Check if it's a subclass of a registered class (recursive) for rcls in cls._abc_registry: if issubclass(subclass, rcls): cls._abc_cache.add(subclass) return True # Check if it's a subclass of a subclass (recursive) for scls in cls.__subclasses__(): if issubclass(subclass, scls): cls._abc_cache.add(subclass) return True # No dice; update negative cache cls._abc_negative_cache.add(subclass) return False class ABC(metaclass=ABCMeta): """Helper class that provides a standard way to create an ABC using inheritance. """ pass
collections.abc.Callableblog
collections.abc.Iterator繼承
collections.abc.Mapping
numbers
以上爲Python提供的經常使用抽象基類,若要了解各抽象基類的相關信息,請參考具體的文檔