Type hints in namedtuple
Solution 1
The prefered Syntax for a typed named tuple since 3.6 is
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int = 1 # Set default value
Point(3) # -> Point(x=3, y=1)
Edit
Starting Python 3.7, consider using dataclasses
(your IDE may not yet support them for static type checking):
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int = 1 # Set default value
Point(3) # -> Point(x=3, y=1)
Solution 2
You can use typing.NamedTuple
From the docs
Typed version of
namedtuple
.
>>> import typing
>>> Point = typing.NamedTuple("Point", [('x', int), ('y', int)])
This is present only in Python 3.5 onwards
Solution 3
Just to be fair, NamedTuple
from typing
:
>>> from typing import NamedTuple
>>> class Point(NamedTuple):
... x: int
... y: int = 1 # Set default value
...
>>> Point(3)
Point(x=3, y=1)
equals to classic namedtuple
:
>>> from collections import namedtuple
>>> p = namedtuple('Point', 'x,y', defaults=(1, ))
>>> p.__annotations__ = {'x': int, 'y': int}
>>> p(3)
Point(x=3, y=1)
So, NamedTuple
is just syntax sugar for namedtuple
Below, you can find a creating NamedTuple
function from the source code of python 3.10
. As we can see, it uses collections.namedtuple
constructor and adds __annotations__
from extracted types:
def _make_nmtuple(name, types, module, defaults = ()):
fields = [n for n, t in types]
types = {n: _type_check(t, f"field {n} annotation must be a type")
for n, t in types}
nm_tpl = collections.namedtuple(name, fields,
defaults=defaults, module=module)
nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = types
return nm_tpl
Related videos on Youtube
Pavel Hanpari
Updated on November 18, 2021Comments
-
Pavel Hanpari over 2 years
Consider following piece of code:
from collections import namedtuple point = namedtuple("Point", ("x:int", "y:int"))
The Code above is just a way to demonstrate as to what I am trying to achieve. I would like to make
namedtuple
with type hints.Do you know any elegant way how to achieve result as intended?
-
JohnE almost 6 yearsAlso, starting with py3.7 you have the dataclass option: docs.python.org/3/library/dataclasses.html
-
-
andilabs about 7 yearsI declared it like this:
GeoPoint = NamedTuple('GeoPoint', [('longitude', float), ('latitude', float)])
then I try geo = GeoPoint(**data) where data is dict containing needed keys and values beingdecimal.Decimal
, and no cast to float happens ;( no typerror either :( :( so how thistyping.NamedTuple
works? see gist.github.com/andilabs/15002176b2bda786b9037077fa06cc71 -
Bhargav Rao about 7 years@andi typing doesn't enforce or cast variables, afaik.
-
Wolfgang Kuehn almost 6 years@JohnE; The OP specifically asked for named tuples. Yes, many use cases of named tuples will be better served by data classes. But to quote the excellent Why not namedtuples: If you want a tuple with names, by all means: go for a namedtuple
-
VARAK over 4 yearsUsing dataclasses, it is not possible to deconstruct the resulting object like you could a Tuple
-
shao.lo over 4 yearsA tuple is immutable. A dataclass is not (by default) It does have the frozen flag which gets close to tuple's behaviour. Just something to be aware of.
-
izkeros over 3 yearsif dataclass works for you, you can go further and use pydantic package to enforce type checking on runtime in elegant way.
-
Marked as Duplicate over 2 yearsIn newer versions you may declare NamedTuples as
Point = typing.NamedTuple("Point", x=int, y=int)
, which is much cleaner and shorter. -
Vichoko over 2 yearsDataclasses aren't subscribable, and they neither are unpackable while iterating as named tuples do so I think they are far from being a perfect alternative.
-
chepner over 2 yearsSyntactic sugar is something the parser can replace with more fundamental syntax.
NamedTuple
is a bit more complicated than that, being a function that actually does something at runtime. -
mrvol over 2 yearsYes, I know what it does do during runtime. It is extracting types and adds them to
__annotations__
attr of just creatednamedtuple
using constructorcollections.namedtuple
. I added that code to the answer for better understanding. -
JWCS over 2 years^ Documentation, discussion, and examples floating around for this syntax is nearly non-existent. I only found it in the cpython typing.py file. It states the syntax is available from 3.6+, and it's at least in the 3.7+ code. Though there doesn't seem to be a cleaner version of this for setting defaults adjacent to the member/type declaration.