Search code examples
inheritancesubclasssupermetaclass

initiate superclass object in subclass


Can someone explain to me what is going for super() in the child_2 class? I find it a bit counter-intuitive that the super() initiation is picking up the convert_id() function in child_2 instead of child_1. I thought by calling super(), it's suppose to use the function in class_1 to initiate the object.

from abc import ABC, abstractmethod

class base(ABC):
    @abstractmethod
    def convert_id(self, id):
        pass

class child_1(base, ABC):
    def __init__(self, id):
        self.new_id = self.convert_id(id)

    def convert_id(self, id):
        return id

class child_2(child_1):
    def __init__(self, id):
        self.id = id
        super().__init__(id=self.id)

    def convert_id(self, id):
        return id+1

test = child_2(0)
print(test.new_id)
1

Solution

  • This is the normal, expected, and essential way of behaving in Object Oriented programming with inheritance.

    The idea is that your specialized classes (the inherited classes), can specialize specific methods. The general pattern is that a method in the superclass can orchestrate the calling of various other methods to perform specific tasks for the instance in question - and, if an specialized subclass cares to refine one of the methods by overriding it, that is the one called.

    In runtime terms, what happens is that the self that child_1.__init__ receives is an instance of child_2 (which also happens to be an instance of child_1) - but an methods called in that received object will be resolved from child_2. That is only "counterintuitive" if you are thinking of "self" in child_1.__init__ as an instance of child_1 instead. That "casting" never takes place, and neither is it naturally feasible in Python.

    Now, if you have a pattern in your code that requires this behavior: that the __init__ in child_1 calls only the methods as defined in child_1, and never an overiden method in a subclass, that is feasible through the mechanism of "name mangling": if a method or attribute starts with two underscores (__), the compiler will bake the class name into that method or attribute name, in a way it won't be overiden by accident (while the hint of the __ makes clear for the programmers that it should not be overiden). In other languages than Python, this behavior is achieved through the use of "private" methods: a method to which the subclasses themselves can't have access (unlike "protected").

    In time: this behavior has nothing to do with the fact ou inherit from abc.ABC or from the custom metaclass used by that - this is how the language works.

    In other words, the behavior you were expecting will take place if you call your method __convert_id instead of convert_id. But keep in mind this is not the natural behavior to have with inheritance, only one possible way that has fewer uses than simply allowing the method to be overiden.