Why does the type hint of a set type variable make the ` mypy ` module not recognize the attributes of a namedtuple in this set type variable?

Advertisements

I have a question about the mypy module. It is demonstrated in the code below:

from typing import Set, NamedTuple
from collections import namedtuple

Student = namedtuple('Student', 'name english math')
students: Set[NamedTuple] = {Student('John', 100, 80),
                             Student('Mary', 90, 90),}
for student in students:
  print(student.name)

When I used the mypy module to check the snippet of code, it reported the following error for the last line:

test.py:8: error: "NamedTuple" has no attribute "name"  [attr-defined]
Found 1 error in 1 file (checked 1 source file)

I also found that this error was not reported after I omitted the type hint for the variable students in line 4 as follows:

from typing import Set, NamedTuple
from collections import namedtuple

Student = namedtuple('Student', 'name english math')
students = {Student('John', 100, 80),
            Student('Mary', 90, 90),}
for student in students:
  print(student.name)

Can anyone kindly tell me why this error occurs? And what is the appropriate way to let the mypy module know the attributes of the namedtuple Student without omitting the type hint for the variable students in a situation like this? Thank you in advance.

>Solution :

You need to annotate students as a set of Students (which you’ve defined as having a name attribute), not the base NamedTuple type (which isn’t specifically associated with your Student namedtuple):

from typing import Set
from collections import namedtuple

Student = namedtuple('Student', 'name english math')
students: Set[Student] = {Student('John', 100, 80),
                             Student('Mary', 90, 90),}
for student in students:
    print(student.name)

If you want to use typing.NamedTuple, you use it as the base class for your specific namedtuple type:

from typing import NamedTuple, Set

class Student(NamedTuple):
    name: str
    english: int
    math: int
    
students: Set[Student] = {Student('John', 100, 80),
                             Student('Mary', 90, 90),}
for student in students:
    print(student.name)

Note that the typing.NamedTuple version has type annotations for the individual attributes; the collections.namedtuple version implicitly types them all as Any.

Leave a ReplyCancel reply