I was reading here, but it's about type hinting for namedtuples.
Is it possible to create a type hint for a List
that contains a namedtuple
?
For example:
firefoxprofile = namedtuple("Profile", ["Name", "Path", "isRelative", "Default"])
# Will contain a list of tuples that represent the firefox profiles.
ffprofiles = [] # -- how would I write the type hint?
ffprofiles.append(Profile(Name='Jason', Path='Profiles/er5rtak4.Jason', isRelative='1', Default=None))
ffprofiles.append(Profile(Name='Sarah', Path='Profiles/23mvfqcj.Sarah', isRelative='1', Default=None))
I tried:
ffprofiles = List[namedtuple("Profile", ["Name", "Path", "isRelative", "Default"])]
but that doesn't work, when I try to update the ffprofiles = []
line with that syntax, I get an exception:
TypeError: descriptor 'append' requires a 'list' object but received a 'Profile'
You don't spell out the named tuple, reference just the name of the type in your List[]
type:
List[firefoxprofile]
Put the type hint after a colon but before the =
when used in an assignment, following PEP 526 Variable Annotations syntax:
ffprofiles: List[firefoxprofile] = []
This sets ffprofiles
to an empty list, and tells any type hint checkers that the contents of the list must be instances of the firefoxprofile
type. If you wanted to provide some initial profiles in that list, just include them in the list literal, no need to append them afterwards.
You assigned the class generated by namedtuple()
to the name firefoxprofile
so that’s what the rest of your code would use to reference it, and not by the name Profile
. You may want to assign the namedtuple()
result to the same name you passed in as the first argument, though, so Profile = namedtuple('Profile', ...)
.
However, you probably also want to use the typing.NamedTuple
class to define your typed named tuple instead; the post you linked to covered this but here it is applied to your example:
from typing import Optional, NamedTuple, List
class FirefoxProfile(NamedTuple):
name: str
path: str
is_relative: bool
default: Optional[str]
ffprofiles: List[FirefoxProfile] = [
FirefoxProfile('Jason', 'Profiles/er5rtak4.Jason', True, None),
# ... and more
]
Defining a class that’s a subclass of typing.NamedTuple
has the same result as using the namedtuple()
function, except the syntax is a lot cleaner, you get to add types for the fields, and you can optionally add a docstring and additional attributes or methods (almost anything that's not a type-hinted attribute or a namedtuple method goes).
Now the type hinting machinery will know much more about what is expected. Not only is it now clear what type of instances the list will contain, the above also documents what attributes the named tuple class supports and what type each those attributes have. I made some educated guesses as to what those types might be. I also used Python's PEP-8 style conventions for the names here, so the named tuple attributes all use lowercase_with_underscores (“snake_case”) rather than CamelCase. The latter should really only be used for class names.