Search code examples
pythonpython-3.xoopsuperclass

Is there a way to reference an object's base __class__ from class scope?


I have a series of classes all, inheriting from one of several possible parents which all share a base class. Each class has a class-scope Dict[str, object] parameters which is based on the base class parameters

from copy import deepcopy


class BaseClass:
    parameters = {
        'example_param1': ParamObject(name='example_param1', editable=True),
    }


class MiddleClass(Baseclass):
    parameters = {
        **deepcopy(Baseclass.parameters),
        'example_param2': ParamObject(name='example_param2', editable=False),
    }


class ChildClass(MiddleClass):
    parameters = {
        **deepcopy(MiddleClass.parameters),
        'example_param3': ParamObject(name='example_param3', editable=True),
    }

This implementation does the job, but I find the **deepcopy(Baseclass.parameters), line unsatisfying. These child classes are going to be edited over time by someone with only a basic understanding of coding so I want to make the code as simple and cut-and-pasteable as possible.

Is there anything I can call at class scope to get the equivilant of super().__class__? I want the user to be able to change the base class from, say, MiddleClass to MiddleClass2 without needing to remember to change the base class in multiple locations.


Solution

  • You could do this with a metaclass. Check all of the classes in the inheritance tree to see if they have the parameters field. If they do, then merge them together and set the property on the class instance.

    class ParamMeta(type):
        def __init__(cls, name, bases, dct):
            class_types = [cls] + list(bases)
            parameters = {}
            for class_type in class_types:
                if hasattr(class_type, "parameters"):
                    parameters.update(class_type.parameters)
            cls.parameters = parameters
            super().__init__(name, bases, dct)
    

    Example:

    class Foo(metaclass=ParamMeta):
        parameters = {"a": "b"}
    
    
    class Bar(Foo):
        pass
    
    
    class Fizz(Bar):
        parameters = {"c": "d"}
    
    
    print(Foo.parameters)
    print(Bar.parameters)
    print(Fizz.parameters)
    

    Outputs:

    {'a': 'b'}
    {'a': 'b'}
    {'c': 'd', 'a': 'b'}