Search code examples
pythondecoratorabc

Do ABCs enforce method decorators?


I'm trying to figure out how to ensure that a method of a class inheriting from an ABC is created using the appropriate decorator. I understand (hopefully) how ABCs work in general.

from abc import ABCMeta, abstractmethod

class MyABC(metaclass=ABCMeta):
    @abstractmethod
    def my_abstract_method(self):
        pass

class MyClass(MyABC):
    pass

MyClass()

This gives "TypeError: Can't instantiate abstract class MyClass with abstract methods my_abstract_method". Great, makes sense. Just create a method with that name.

class MyClass(MyABC):
    def my_abstract_method(self):
        pass

MyClass()

Boom. You're done. But what about this case?

from abc import ABCMeta, abstractmethod

class MyABC(metaclass=ABCMeta):    
    @property
    @abstractmethod
    def my_attribute(self):
        pass

class MyClass(MyABC):
    def my_attribute(self):
        pass

MyClass()

The MyClass() call works even though my_attribute is not a property. I guess in the end all ABCs do is ensure that a method with a given name exists. Thats it. If you want more from it, you have to look at MyABC's source code and read the documentation. The decorators and comments there will inform you of how you need to construct your sub-class.

Do I have it right or am I missing something here?


Solution

  • You're correct that ABCs do not enforce that. There isn't a way to enforce something like "has a particular decorator". Decorators are just functions that return objects (e.g., property returns a property object). ABCMeta doesn't do anything to ensure that the defined attributes on the class are anything in particular; it just makes sure they are there. This "works" without errors:

    class MyABC(metaclass=ABCMeta):
        @abstractmethod
        def my_abstract_method(self):
            pass
    
    class MyClass(MyABC):
        my_abstract_method = 2
    
    MyClass()
    

    That is, ABCMeta doesn't even ensure that the abstract method as provided on the subclass is a method at all. There just has to be an attribute of some kind with that name,

    You could certainly write your own metaclass that does more sophisticated checking to ensure that certain attributes have certain kinds of values, but that's beyond the scope of ABCMeta.