mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
This commit is contained in:
parent
49e8f2d204
commit
2f84144235
2 changed files with 52 additions and 36 deletions
|
@ -1865,6 +1865,20 @@ class NamedTupleTests(BaseTestCase):
|
||||||
self.assertEqual(CoolEmployee._fields, ('name', 'cool'))
|
self.assertEqual(CoolEmployee._fields, ('name', 'cool'))
|
||||||
self.assertEqual(CoolEmployee._field_types, dict(name=str, cool=int))
|
self.assertEqual(CoolEmployee._field_types, dict(name=str, cool=int))
|
||||||
|
|
||||||
|
@skipUnless(PY36, 'Python 3.6 required')
|
||||||
|
def test_namedtuple_keyword_usage(self):
|
||||||
|
LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int)
|
||||||
|
nick = LocalEmployee('Nick', 25)
|
||||||
|
self.assertIsInstance(nick, tuple)
|
||||||
|
self.assertEqual(nick.name, 'Nick')
|
||||||
|
self.assertEqual(LocalEmployee.__name__, 'LocalEmployee')
|
||||||
|
self.assertEqual(LocalEmployee._fields, ('name', 'age'))
|
||||||
|
self.assertEqual(LocalEmployee._field_types, dict(name=str, age=int))
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
NamedTuple('Name', [('x', int)], y=str)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
NamedTuple('Name', x=1, y='a')
|
||||||
|
|
||||||
def test_pickle(self):
|
def test_pickle(self):
|
||||||
global Emp # pickle wants to reference the class by name
|
global Emp # pickle wants to reference the class by name
|
||||||
Emp = NamedTuple('Emp', [('name', str), ('id', int)])
|
Emp = NamedTuple('Emp', [('name', str), ('id', int)])
|
||||||
|
|
|
@ -1875,6 +1875,8 @@ class Type(Generic[CT_co], extra=type):
|
||||||
|
|
||||||
|
|
||||||
def _make_nmtuple(name, types):
|
def _make_nmtuple(name, types):
|
||||||
|
msg = "NamedTuple('Name', [(f0, t0), (f1, t1), ...]); each t must be a type"
|
||||||
|
types = [(n, _type_check(t, msg)) for n, t in types]
|
||||||
nm_tpl = collections.namedtuple(name, [n for n, t in types])
|
nm_tpl = collections.namedtuple(name, [n for n, t in types])
|
||||||
nm_tpl._field_types = dict(types)
|
nm_tpl._field_types = dict(types)
|
||||||
try:
|
try:
|
||||||
|
@ -1884,19 +1886,24 @@ def _make_nmtuple(name, types):
|
||||||
return nm_tpl
|
return nm_tpl
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info[:2] >= (3, 6):
|
_PY36 = sys.version_info[:2] >= (3, 6)
|
||||||
|
|
||||||
|
|
||||||
class NamedTupleMeta(type):
|
class NamedTupleMeta(type):
|
||||||
|
|
||||||
def __new__(cls, typename, bases, ns, *, _root=False):
|
def __new__(cls, typename, bases, ns):
|
||||||
if _root:
|
if ns.get('_root', False):
|
||||||
return super().__new__(cls, typename, bases, ns)
|
return super().__new__(cls, typename, bases, ns)
|
||||||
|
if not _PY36:
|
||||||
|
raise TypeError("Class syntax for NamedTuple is only supported"
|
||||||
|
" in Python 3.6+")
|
||||||
types = ns.get('__annotations__', {})
|
types = ns.get('__annotations__', {})
|
||||||
return _make_nmtuple(typename, types.items())
|
return _make_nmtuple(typename, types.items())
|
||||||
|
|
||||||
class NamedTuple(metaclass=NamedTupleMeta, _root=True):
|
class NamedTuple(metaclass=NamedTupleMeta):
|
||||||
"""Typed version of namedtuple.
|
"""Typed version of namedtuple.
|
||||||
|
|
||||||
Usage::
|
Usage in Python versions >= 3.6::
|
||||||
|
|
||||||
class Employee(NamedTuple):
|
class Employee(NamedTuple):
|
||||||
name: str
|
name: str
|
||||||
|
@ -1909,30 +1916,25 @@ if sys.version_info[:2] >= (3, 6):
|
||||||
The resulting class has one extra attribute: _field_types,
|
The resulting class has one extra attribute: _field_types,
|
||||||
giving a dict mapping field names to types. (The field names
|
giving a dict mapping field names to types. (The field names
|
||||||
are in the _fields attribute, which is part of the namedtuple
|
are in the _fields attribute, which is part of the namedtuple
|
||||||
API.) Backward-compatible usage::
|
API.) Alternative equivalent keyword syntax is also accepted::
|
||||||
|
|
||||||
|
Employee = NamedTuple('Employee', name=str, id=int)
|
||||||
|
|
||||||
|
In Python versions <= 3.5 use::
|
||||||
|
|
||||||
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
|
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
|
||||||
"""
|
"""
|
||||||
|
_root = True
|
||||||
|
|
||||||
def __new__(self, typename, fields):
|
def __new__(self, typename, fields=None, **kwargs):
|
||||||
return _make_nmtuple(typename, fields)
|
if kwargs and not _PY36:
|
||||||
else:
|
raise TypeError("Keyword syntax for NamedTuple is only supported"
|
||||||
def NamedTuple(typename, fields):
|
" in Python 3.6+")
|
||||||
"""Typed version of namedtuple.
|
if fields is None:
|
||||||
|
fields = kwargs.items()
|
||||||
Usage::
|
elif kwargs:
|
||||||
|
raise TypeError("Either list of fields or keywords"
|
||||||
Employee = typing.NamedTuple('Employee', [('name', str), 'id', int)])
|
" can be provided to NamedTuple, not both")
|
||||||
|
|
||||||
This is equivalent to::
|
|
||||||
|
|
||||||
Employee = collections.namedtuple('Employee', ['name', 'id'])
|
|
||||||
|
|
||||||
The resulting class has one extra attribute: _field_types,
|
|
||||||
giving a dict mapping field names to types. (The field names
|
|
||||||
are in the _fields attribute, which is part of the namedtuple
|
|
||||||
API.)
|
|
||||||
"""
|
|
||||||
return _make_nmtuple(typename, fields)
|
return _make_nmtuple(typename, fields)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue