Home > Software design >  Get mangled attribute value of a parent class outside of a class
Get mangled attribute value of a parent class outside of a class

Time:11-20

Imagine a parent class which has a mangled attribute, and a child class:

class Foo:

    def __init__(self):
        self.__is_init = False

    async def init(self):
        # Some custom logic here, not important
        self.__is_init = True


class Bar(Foo):
    ...


# Create class instance.
bar = Bar()
# How access `__is_init` of the parent class from the child instance?

How can I get a __is_init value from a parent (Foo) class?


Obviously, I can bar._Foo__is_init in this example, but the problem is that class name is dynamic and I need a general purpose solution that will work with any passed class name.

CodePudding user response:

The solution I see now is iterating over parent classes, and building a mangled attribute name dynamically:

from contextlib import suppress

class MangledAttributeError(Exception):
    ...

def getattr_mangled(object_: object, name: str) -> str:
    for cls_ in getattr(object_, "__mro__", None) or object_.__class__.__mro__:
        with suppress(AttributeError):
            return getattr(object_, f"_{cls_.__name__}{name}")
    raise MangledAttributeError(f"{type(object_).__name__} object has no attribute '{name}'")

Checking that this works:

class Foo:

    def __init__(self):
        self.__is_init = False

    async def init(self):
        self.__is_init = True

class Bar(Foo):

    def __init__(self):
        super().__init__()

bar = Bar()
is_init = getattr_mangled(bar, "__is_init")
print(f"is_init: {is_init}")  # Will print `False` which is a correct value in this example

CodePudding user response:

class Foo:

    def __init__(self):
        self.__is_init = False

    async def init(self):
        self.__is_init = True

class Bar(Foo):

    def getattr_mangled(self, attr:str):
        for i in self.__dict__.keys():
            if attr in i:
                return getattr(self,i)
                # return self.__dict__[i] #or like this



bar = Bar()
print(bar.getattr_mangled('__is_init')) #False

if there is a need in __init__ in Bar we should of course initiate Foo's init too by: super().__init__()

When Foo's init is run, self namespace already has attribute name we need in the form we need it (like_PARENT_CLASS_NAME__attrname).
And we can just get it from self namespace without even knowing what parent class name is.

  • Related