Search code examples
pythonclassinspect

How to get all declared or just typed parameters of a class


How to write a function that prints out all attributes of a class with types?

class Parent:
    parent_param: str
    parent_default: str | None = None

    def find_params_meta(self):
        ...
        # enter magic code, filter out methods and attributes starting with `"_"`

class Child(Parent):
    child_param: str
    _params_meta: dict[str, Any] | None = None

    def __init__(self, parent_param: str, child_param: str):
        self._params_meta = self.find_params_meta()
        self.child_param = child_param
        self.parent_param = parent_param

assert Child("parent param", "child param")._params_meta == {
    "parent_param": {"types": [str]},
    "parent_default": {"types": [str, None], "default": None},
    "child_param": {"types": [str]},
}

The parent_param and child_param attributes are not instantiated. getattr(self, "parent_param") raises the AttributeError: 'Child' object has no attribute 'parent_param'. type(self).__dict__, dir(self) or inspect.getmembers(self) are not printing them. inspect.get_annotations(type(self)) is closer as it prints {'child_param': <class 'str'>, ...}, but it does not return Parent's attributes.


Solution

  • Building on the code you posted:

    class Parent:
        ...
    
        @classmethod
        def find_params_meta(cls):
            return {
                k: v
                for c in reversed(cls.__mro__)
                for k, v in inspect.get_annotations(c).items()
            }
    
    

    Edit: added reversed since you probably want to give preference to types set on child classes... though it is probably not valid to override the type for a child class (Liskov Substitution Principle)