Search code examples
pythonclasslist-comprehensionnamedtuple

How to add a list of field names to a class based on NamedTuple?


I have a basic class like this:

from typing import NamedTuple

class A(NamedTuple):
    f1: str = ""


aa = A("haha")
print(aa)

Now suppose I have a list of more fields that I want to use in Class A, essentially:

more_field_names = ['f2', 'f3', 'f4']

and I want to make Class A look like this, but without manually typing all the field names:

class A(NamedTuple):
    f1: str = ""
    f2: str = ""
    f3: str = ""
    f4: str = ""

Is there a way to use something like list comprehension to add each field names to the Class A definition?


Solution

  • I'm not entirely sure if this is what you're looking for, but you can dynamically generate the class definition to copy-paste into a python file, based on a list of fields that you want to add (assuming you have a lot of same-type fields to add):

    def gen_named_tuple_schema(fields: list[str], class_name='A'):
        fields = '\n'.join(f"    {f}: str = ''" for f in fields)
        return f'class {class_name}(NamedTuple):\n{fields}'
    

    Then you can use it like so:

    print(gen_named_tuple_schema(['f1', 'f2', 'f3', 'f4']))
    

    Output:

    class A(NamedTuple):
        f1: str = ''
        f2: str = ''
        f3: str = ''
        f4: str = ''
    

    I would add that, even though it is technically possible to run exec() on the generated code, I would honestly not recommend it. The reason is that type checkers won't know the type of A by default, so they won't be able to offer field auto-completion and type checking.

    For example, in my case PyCharm does not complain at all if I do this:

    return_dict = {}
    exec(gen_named_tuple_schema(['f1', 'f2', 'f3', 'f4']),
         {'NamedTuple': typing.NamedTuple},
         return_dict)
    A = return_dict['A']  # my type checker: what is A?
    
    print(A(1, '2', 3, '4'))   # A(f1=1, f2='2', f3=3, f4='4')