Search code examples
pythonooppython-3.6metaprogrammingabc

Assertion in abstract base class?


Essentially what I want is to require that subclasses of an abstract base classes not only implement certain attributes or methods, but can also make requirements on those, such as data types or allowed values.

For example, let's say I want to require classes that have a name and that that name starts with the letter 'a':

from abc import ABC, abstractproperty

class Base(ABC):
     @abstractproperty
     def name(self):
         assert self.name[0] == 'a' # or similar; help needed here

class Derived1(Base):
    name = 'albert' # I want this class definition to work

class Derived2(Base):
    name = 'john' # I want this class definition to fail the 'a' assertion

Where/how would I assert this in the base class?


Solution

  • Use __init_subclass__ to enforce restrictions on class attributes.

    class Base:
        def __init_subclass__(cls):
            try:
                name = cls.name
            except AttributeError:
                raise ValueError("No name attribute")
    
            if name[0] != "a":
                raise ValueError("first letter of name is not 'a'")
    
    
    class Derived1(Base):
        name = 'albert' # OK
    
    class Derived2(Base):
        name = 'john' # Fails due to first letter 'j'
    
    # Fails because Derived3.name is never defined
    class Derived3(Base):
        pass