How can I return the attributes for all class in the inheritance chain?

Viewed 75

If you have a class hierarchy and some class attribute is overridden in child class then the user of child class should not care what was the value of this attribute in parent classes.

But this is what I want to achieve:

class A:
    _ITEM = "A"

    @classmethod
    def getClassPath(cls):
        ???


class B(A):
    _ITEM = "B"


class C(B):
    _ITEM = "C"


# expected behavior:
A.getClassPath()  # "/A"
B.getClassPath()  # "/A/B"
C.getClassPath()  # "/A/B/C"

My original problem is a little more complicated, but it is reduced to this: get _ITEM attributes from all the classes in hierarchy and combine them somehow.

How can I do it? There is no multiple inheritance in my case.

1 Answers

you can use mro (method resolution order) to access attributes in the inheritance chain. The simple case:

class A:
    _ITEM = "A"
    
    @classmethod
    def get_class_path(cls):
        result = cls.mro()[:-1]
        result = [res._ITEM for res in reversed(result)]
        result = "/" + "/".join(result)
        return result

If, additionally, you want to skip classes that don't have _ITEM, you can modify slightly with vars():

class A:
    _ITEM = "attr_A"

    @classmethod
    def get_class_path(cls):
        mro_list = reversed(cls.mro()[:-1])

        result = []
        for obj in mro_list:
            if "_ITEM" in vars(obj):
                result.append(obj._ITEM)

        result = "/" + "/".join(result)
        return result

class B(A):
    # _ITEM = "attr_B"
    pass

class C(B):
    _ITEM = "attr_C"

output:

B.get_class_path() # returns '/attr_A'
C.get_class_path() # returns '/attr_A/attr_C'
Related