Determine if a Python class is an Abstract Base Class or Concrete

后端 未结 3 1436
无人及你
无人及你 2020-12-16 09:58

My Python application contains many abstract classes and implementations. For example:

import abc
import datetime
         


        
3条回答
  •  心在旅途
    2020-12-16 10:21

    Abstract classes and their concrete implementations have an __abstractmethods__ attribute containing the names of abstract methods and properties that have not been implemented. This behaviour is described in PEP 3199:

    Implementation: The @abstractmethod decorator sets the function attribute __isabstractmethod__ to the value True. The ABCMeta.__new__ method computes the type attribute __abstractmethods__ as the set of all method names that have an __isabstractmethod__ attribute whose value is true. It does this by combining the __abstractmethods__ attributes of the base classes, adding the names of all methods in the new class dict that have a true __isabstractmethod__ attribute, and removing the names of all methods in the new class dict that don't have a true __isabstractmethod__ attribute. If the resulting __abstractmethods__ set is non-empty, the class is considered abstract, and attempts to instantiate it will raise TypeError. (If this were implemented in CPython, an internal flag Py_TPFLAGS_ABSTRACT could be used to speed up this check.)

    So in concrete classes, this attribute either will not exist or will be an empty set. This is easy to check:

    def is_abstract(cls):
        if not hasattr(cls, "__abstractmethods__"):
            return False # an ordinary class
        elif len(cls.__abstractmethods__) == 0:
            return False # a concrete implementation of an abstract class
        else:
            return True # an abstract class
    

    Or more succinctly:

    def is_abstract(cls):
        return bool(getattr(cls, "__abstractmethods__", False))
    
    print(is_abstract(object))                 # False
    print(is_abstract(MessageDisplay))         # True
    print(is_abstract(FriendlyMessageDisplay)) # True
    print(is_abstract(FriendlyMessagePrinter)) # False
    

提交回复
热议问题