The typing
module documentation says that the two code snippets below are equivalent.
from typing import NamedTuple
class Employee(NamedTuple):
name: str
id: int
and
from collections import namedtuple
Employee = namedtuple('Employee', ['name', 'id'])
Are they the exact same thing or, if not, what are the differences between the two implementations?
The type generated by subclassing
typing.NamedTuple
is equivalent to acollections.namedtuple
, but with__annotations__
,_field_types
and_field_defaults
attributes added. The generated code will behave the same, for all practical purposes, since nothing in Python currently acts on those typing related attributes (your IDE might use them, though).As a developer, using the
typing
module for your namedtuples allows a more natural declarative interface:collections.namedtuple
got a newdefaults
keyword so this is no longer an advantage)As before, your class will be a subclass of
tuple
, and instances will be instances oftuple
as usual. Interestingly, your class will not be a subclass ofNamedTuple
:If you want to know why, read on for more info about the current implementation detail.
typing.NamedTuple
is a class, it uses metaclasses and a custom__new__
to handle the annotations, and then it delegates tocollections.namedtuple
, anyway, to build and return the type. As you may have guessed from the lowercased name convention,collections.namedtuple
is not a type/class - it's a factory function. It works by building up a string of Python source code, and then callingexec
on this string. The generated constructor is plucked out of a namespace and included in a 3-argument invocation of the metaclasstype
to build and return your class. This explains the weird inheritance breakage seen above,NamedTuple
uses a metaclass in order to use a different metaclass to instantiate the class object.