Search code examples
pythonmetaclassabc

Can I write abc.ABC without resorting to metaclasses in Python 3.6?


Python 3.6 added PEP 487, which adds an __init_subclass__ method among other things. Is it possible to write a version of ABC that doesn't use a metaclass?


Solution

  • If all you care about is the check for abstract methods, then yes. Just move the abstract method set computation to the __init_subclass__ method:

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        # Compute set of abstract method names
        abstracts = {name
                     for name, value in vars(cls).items()
                     if getattr(value, "__isabstractmethod__", False)}
        for base in cls.__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)
    

    The base object.__new__ implementation then uses an non-empty __abstractmethods__ set to prevent instantiation.

    But ABCs also support virtual subclass registration; the two hook methods this requires have to be implemented on the metaclass.