Search code examples
pythoninner-classesabc

Is there some mechanism to enforce nested interfaces are implemented in abstract classes in Python?


I want to create a class that has some nested class that defines some contract in Python. A tenable example is a typed config object. My attempt at this is below:

from typing import Mapping
from abc import ABCMeta, abstractmethod

class BaseClass(metaclass=ABCMeta):
    # If you want to implement BaseClass, you must also implement BaseConfig
    class BaseConfig(metaclass=ABCMeta):
        @abstractmethod
        def to_dict(self) -> Mapping:
            """Converts the config to a dictionary"""

But unfortunately I can instantiate a subclass of BaseClass without implementing BaseConfig:

class Foo(BaseClass):
    pass

if __name__ == "__main__":
    foo = Foo()

Is there some way to enforce that a subclass must implement an inner class, too?


Solution

  • It doesn't seem like this is currently possible. The closest thing is to create two abstract classes (corresponding to outer and inner classes) and to force the implementer to provide the cls constructor for the concrete inner class; e.g.:

    from abc import ABCMeta, abstractmethod
    
    class Inner(metaclass=ABCMeta):
        @abstractmethod
        def __str__(self):
            pass
    
    class Outer(metaclass=ABCMeta):
        inner_cls = Inner
    
        def shout(self, *args, **kwargs):
            inner = self.inner_cls(*args, **kwargs)
            print(f"My inner is {inner}!!!")
    
    class FooInner(Inner):
        def __str__(self):
            return "FooInner"
    
    class FooOuter(Outer):
        inner_cls = FooInner
    
    

    This requires Inner to have at least one abstractmethod otherwise it can be instantiated as a default inner_cls implementation.