Search code examples
pythonoopinheritancesubclass

Setup automatic inheritance of parent class' subclass in Python


When running this code, the print displays the message "no number found in class A", although in fact it was not found in an object of class B. The aim is to change only the Base class in such a way that, when inheriting from it, descendants create their own NotFoundError exception inherited from Base.

class Base:
    class NotFoundError(Exception):
        pass

    def __init__(self, numbers: list[int]):
        self.numbers = numbers

    def pop_by_val(self, number: int):
        try:
            self.numbers.remove(number)
        except ValueError:
            raise self.NotFoundError()


class A(Base):
    pass


class B(Base):
    pass


a = A([1, 2])
b = B([1, 2])

try:
    a.pop_by_val(1)
    b.pop_by_val(3)
except A.NotFoundError:
    print("no number found in class A")
except B.NotFoundError:
    print("no number found in class B")

I guess it can be fixed by some kind of init/new dunders' customization, but I haven't succeeded in my tries


Solution

  • There's no automatic definition of new, inherited class attributes, but you can define __init_subclass__ to define them for you.

    class Base:
        class NotFoundError(Exception):
            pass
    
        def __init_subclass__(cls, **kwargs):
            super().__init_subclass__(**kwargs)
            class NotFoundError(Base.NotFoundError):
                pass
            cls.NotFoundError = NotFoundError
    
        def __init__(self, numbers: list[int]):
            self.numbers = numbers
    
        def pop_by_val(self, number: int):
            try:
                self.numbers.remove(number)
            except ValueError:
                raise self.NotFoundError()
    

    (This is basically doing the same thing as @kindall's answer, but avoids using a metaclass. Prefer __init_subclass__ where possible to make it easier for your class to interact with more classes, as metaclasses don't compose well.)