@@ -1702,51 +1702,41 @@ def __round__(self, ndigits: int = 0) -> T_co:
17021702 pass
17031703
17041704
1705- def _make_nmtuple (name , types ):
1706- msg = "NamedTuple('Name', [(f0, t0), (f1, t1), ...]); each t must be a type"
1707- types = [(n , _type_check (t , msg )) for n , t in types ]
1708- nm_tpl = collections .namedtuple (name , [n for n , t in types ])
1709- nm_tpl .__annotations__ = dict (types )
1710- try :
1711- nm_tpl .__module__ = sys ._getframe (2 ).f_globals .get ('__name__' , '__main__' )
1712- except (AttributeError , ValueError ):
1713- pass
1705+ def _make_nmtuple (name , types , module , defaults = ()):
1706+ fields = [n for n , t in types ]
1707+ types = {n : _type_check (t , f"field { n } annotation must be a type" )
1708+ for n , t in types }
1709+ nm_tpl = collections .namedtuple (name , fields ,
1710+ defaults = defaults , module = module )
1711+ nm_tpl .__annotations__ = nm_tpl .__new__ .__annotations__ = types
17141712 return nm_tpl
17151713
17161714
17171715# attributes prohibited to set in NamedTuple class syntax
1718- _prohibited = {'__new__' , '__init__' , '__slots__' , '__getnewargs__' ,
1719- '_fields' , '_field_defaults' ,
1720- '_make' , '_replace' , '_asdict' , '_source' }
1716+ _prohibited = frozenset ( {'__new__' , '__init__' , '__slots__' , '__getnewargs__' ,
1717+ '_fields' , '_field_defaults' ,
1718+ '_make' , '_replace' , '_asdict' , '_source' })
17211719
1722- _special = {'__module__' , '__name__' , '__annotations__' }
1720+ _special = frozenset ( {'__module__' , '__name__' , '__annotations__' })
17231721
17241722
17251723class NamedTupleMeta (type ):
17261724
17271725 def __new__ (cls , typename , bases , ns ):
1728- if ns .get ('_root' , False ):
1729- return super ().__new__ (cls , typename , bases , ns )
1730- if len (bases ) > 1 :
1731- raise TypeError ("Multiple inheritance with NamedTuple is not supported" )
1732- assert bases [0 ] is NamedTuple
1726+ assert bases [0 ] is _NamedTuple
17331727 types = ns .get ('__annotations__' , {})
1734- nm_tpl = _make_nmtuple (typename , types .items ())
1735- defaults = []
1736- defaults_dict = {}
1728+ default_names = []
17371729 for field_name in types :
17381730 if field_name in ns :
1739- default_value = ns [field_name ]
1740- defaults .append (default_value )
1741- defaults_dict [field_name ] = default_value
1742- elif defaults :
1743- raise TypeError ("Non-default namedtuple field {field_name} cannot "
1744- "follow default field(s) {default_names}"
1745- .format (field_name = field_name ,
1746- default_names = ', ' .join (defaults_dict .keys ())))
1747- nm_tpl .__new__ .__annotations__ = dict (types )
1748- nm_tpl .__new__ .__defaults__ = tuple (defaults )
1749- nm_tpl ._field_defaults = defaults_dict
1731+ default_names .append (field_name )
1732+ elif default_names :
1733+ raise TypeError (f"Non-default namedtuple field { field_name } "
1734+ f"cannot follow default field"
1735+ f"{ 's' if len (default_names ) > 1 else '' } "
1736+ f"{ ', ' .join (default_names )} " )
1737+ nm_tpl = _make_nmtuple (typename , types .items (),
1738+ defaults = [ns [n ] for n in default_names ],
1739+ module = ns ['__module__' ])
17501740 # update from user namespace without overriding special namedtuple attributes
17511741 for key in ns :
17521742 if key in _prohibited :
@@ -1756,7 +1746,7 @@ def __new__(cls, typename, bases, ns):
17561746 return nm_tpl
17571747
17581748
1759- class NamedTuple (metaclass = NamedTupleMeta ):
1749+ def NamedTuple (typename , fields = None , / , ** kwargs ):
17601750 """Typed version of namedtuple.
17611751
17621752 Usage in Python versions >= 3.6::
@@ -1780,15 +1770,26 @@ class Employee(NamedTuple):
17801770
17811771 Employee = NamedTuple('Employee', [('name', str), ('id', int)])
17821772 """
1783- _root = True
1784-
1785- def __new__ (cls , typename , fields = None , / , ** kwargs ):
1786- if fields is None :
1787- fields = kwargs .items ()
1788- elif kwargs :
1789- raise TypeError ("Either list of fields or keywords"
1790- " can be provided to NamedTuple, not both" )
1791- return _make_nmtuple (typename , fields )
1773+ if fields is None :
1774+ fields = kwargs .items ()
1775+ elif kwargs :
1776+ raise TypeError ("Either list of fields or keywords"
1777+ " can be provided to NamedTuple, not both" )
1778+ try :
1779+ module = sys ._getframe (1 ).f_globals .get ('__name__' , '__main__' )
1780+ except (AttributeError , ValueError ):
1781+ module = None
1782+ return _make_nmtuple (typename , fields , module = module )
1783+
1784+ _NamedTuple = type .__new__ (NamedTupleMeta , 'NamedTuple' , (), {})
1785+
1786+ def _namedtuple_mro_entries (bases ):
1787+ if len (bases ) > 1 :
1788+ raise TypeError ("Multiple inheritance with NamedTuple is not supported" )
1789+ assert bases [0 ] is NamedTuple
1790+ return (_NamedTuple ,)
1791+
1792+ NamedTuple .__mro_entries__ = _namedtuple_mro_entries
17921793
17931794
17941795def _dict_new (cls , / , * args , ** kwargs ):
0 commit comments