@@ -1702,51 +1702,41 @@ def __round__(self, ndigits: int = 0) -> T_co:
1702
1702
pass
1703
1703
1704
1704
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
1714
1712
return nm_tpl
1715
1713
1716
1714
1717
1715
# 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' })
1721
1719
1722
- _special = {'__module__' , '__name__' , '__annotations__' }
1720
+ _special = frozenset ( {'__module__' , '__name__' , '__annotations__' })
1723
1721
1724
1722
1725
1723
class NamedTupleMeta (type ):
1726
1724
1727
1725
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
1733
1727
types = ns .get ('__annotations__' , {})
1734
- nm_tpl = _make_nmtuple (typename , types .items ())
1735
- defaults = []
1736
- defaults_dict = {}
1728
+ default_names = []
1737
1729
for field_name in types :
1738
1730
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__' ])
1750
1740
# update from user namespace without overriding special namedtuple attributes
1751
1741
for key in ns :
1752
1742
if key in _prohibited :
@@ -1756,7 +1746,7 @@ def __new__(cls, typename, bases, ns):
1756
1746
return nm_tpl
1757
1747
1758
1748
1759
- class NamedTuple (metaclass = NamedTupleMeta ):
1749
+ def NamedTuple (typename , fields = None , / , ** kwargs ):
1760
1750
"""Typed version of namedtuple.
1761
1751
1762
1752
Usage in Python versions >= 3.6::
@@ -1780,15 +1770,26 @@ class Employee(NamedTuple):
1780
1770
1781
1771
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
1782
1772
"""
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
1792
1793
1793
1794
1794
1795
def _dict_new (cls , / , * args , ** kwargs ):
0 commit comments