How to define an abstract metaclass in python

Viewed 489

When defining an abstract metaclass in python and instantiating it like this:

from abc import ABC, abstractmethod


class AbstractMetaClass(type, ABC):
    @abstractmethod
    def func(self):
        pass


class MyClass(metaclass=AbstractMetaClass):
    pass

I would have expected my code to fail, since MyClass is an instance of an abstract class. Instead it runs with no problems. What is happening and how can I do this?

1 Answers

Well, you simply found out it does not work. What you are thinking about makes sense: maybe it should fail. It is just that abstract classes are not designed to work as metaclasses, and work collaboratively with "type". I actually find incredible as most Python object mechanisms happen to "just work" when used with metaclasses - including properties, special dunder methods like __getitem__ and operator methods and so on. You just hit one thing that happened not to work.

If your design really makes sense, you may just want to manually make the check for abstract methods on your "abstract metaclass" __init__ method:

from abc import classmethod

class AbstractMetaClass(type):

    def __init__(cls, name, bases, ns, **kwargs):
        for meth_name, meth in cls.__class__.__dict__.items():
            if getattr(meth, "__isabstractmethod__", False):
                raise TypeError(f"Can't create new class {name} with no abstract classmethod {meth_name} redefined in the metaclass")
        return super().__init__(name, bases, ns, **kwargs)
        
    @abstractmethod
    def func(cls):
        pass

note that for clarity, it is better that ordinary methods on a metaclass have "cls" as the first argument rather than "self" (althought that might be a personal taste)

Related