Skip to content
Advertisement

Define Python type hints in for-loop inside class body

I have the following code in Python:

class ModuleA:
    """This is a reusable element to compose larger designs with"""


class ModuleB:
    """Another reusable element"""


class MyDesign:
    a: ModuleA
    b0: ModuleB
    b1: ModuleB
    b2: ModuleB

The type hints are used upon instantiation of MyDesign to dynamically add instances of the various Modules. I chose this syntax because the class MyDesign is really just a “template” defining what Modules it’s composed of, but the instantiation of modules needs some arguments only available when MyDesign is being instantiated.

I would like to simplify the definition of MyDesign into something like

class MyDesign:
    a: ModuleA


# define repetitive patterns in a loop
for i in range(2):
    MyDesign.__type_hints__[f"b{i}"] = ModuleB

Is this possible?

Advertisement

Answer

Basically what you want is to dynamically modify the type hints in a class. You can achieve that by modifying the annotations__ property of the class like so:

from typing import get_type_hints

class ModuleA:
    """This is a reusable element to compose larger designs with"""


class ModuleB:
    """Another reusable element"""


class MyDesign:
    a: ModuleA
    b0: ModuleA
    b1: ModuleA
    b2: ModuleA

if __name__ == '__main__':
    print(get_type_hints(MyDesign))
    for i in range(2):
        MyDesign.__annotations__[f"b{i}"] = ModuleB

    print(get_type_hints(MyDesign))

result of running this code:

{'a': <class '__main__.ModuleA'>, 'b0': <class '__main__.ModuleA'>, 'b1': <class '__main__.ModuleA'>, 'b2': <class '__main__.ModuleA'>}
{'a': <class '__main__.ModuleA'>, 'b0': <class '__main__.ModuleB'>, 'b1': <class '__main__.ModuleB'>, 'b2': <class '__main__.ModuleA'>}

if you want to add the class members dynamically you can use this code:

for i in range(2):
    MyDesign.a = lambda: None
    setattr(MyDesign.a, f"b{i}", None)
    MyDesign.__annotations__[f"b{i}"] = ModuleB

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement