mirror of https://github.com/python/cpython
Issue #28556: allow default values in class form of NamedTuple -- Jelle Zijlstra
This commit is contained in:
parent
37f183d43d
commit
3c268be885
|
@ -1400,6 +1400,10 @@ class G(Generic[T]):
|
|||
class CoolEmployee(NamedTuple):
|
||||
name: str
|
||||
cool: int
|
||||
|
||||
class CoolEmployeeWithDefault(NamedTuple):
|
||||
name: str
|
||||
cool: int = 0
|
||||
"""
|
||||
|
||||
if PY36:
|
||||
|
@ -1959,6 +1963,28 @@ class NamedTupleTests(BaseTestCase):
|
|||
collections.OrderedDict(name=str, cool=int))
|
||||
self.assertIs(CoolEmployee._field_types, CoolEmployee.__annotations__)
|
||||
|
||||
@skipUnless(PY36, 'Python 3.6 required')
|
||||
def test_annotation_usage_with_default(self):
|
||||
jelle = CoolEmployeeWithDefault('Jelle')
|
||||
self.assertIsInstance(jelle, CoolEmployeeWithDefault)
|
||||
self.assertIsInstance(jelle, tuple)
|
||||
self.assertEqual(jelle.name, 'Jelle')
|
||||
self.assertEqual(jelle.cool, 0)
|
||||
cooler_employee = CoolEmployeeWithDefault('Sjoerd', 1)
|
||||
self.assertEqual(cooler_employee.cool, 1)
|
||||
|
||||
self.assertEqual(CoolEmployeeWithDefault.__name__, 'CoolEmployeeWithDefault')
|
||||
self.assertEqual(CoolEmployeeWithDefault._fields, ('name', 'cool'))
|
||||
self.assertEqual(CoolEmployeeWithDefault._field_types, dict(name=str, cool=int))
|
||||
self.assertEqual(CoolEmployeeWithDefault._field_defaults, dict(cool=0))
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
exec("""
|
||||
class NonDefaultAfterDefault(NamedTuple):
|
||||
x: int = 3
|
||||
y: int
|
||||
""")
|
||||
|
||||
@skipUnless(PY36, 'Python 3.6 required')
|
||||
def test_namedtuple_keyword_usage(self):
|
||||
LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int)
|
||||
|
|
|
@ -1959,7 +1959,22 @@ class NamedTupleMeta(type):
|
|||
raise TypeError("Class syntax for NamedTuple is only supported"
|
||||
" in Python 3.6+")
|
||||
types = ns.get('__annotations__', {})
|
||||
return _make_nmtuple(typename, types.items())
|
||||
nm_tpl = _make_nmtuple(typename, types.items())
|
||||
defaults = []
|
||||
defaults_dict = {}
|
||||
for field_name in types:
|
||||
if field_name in ns:
|
||||
default_value = ns[field_name]
|
||||
defaults.append(default_value)
|
||||
defaults_dict[field_name] = default_value
|
||||
elif defaults:
|
||||
raise TypeError("Non-default namedtuple field {field_name} cannot follow default"
|
||||
" field(s) {default_names}"
|
||||
.format(field_name=field_name,
|
||||
default_names=', '.join(defaults_dict.keys())))
|
||||
nm_tpl.__new__.__defaults__ = tuple(defaults)
|
||||
nm_tpl._field_defaults = defaults_dict
|
||||
return nm_tpl
|
||||
|
||||
class NamedTuple(metaclass=NamedTupleMeta):
|
||||
"""Typed version of namedtuple.
|
||||
|
|
Loading…
Reference in New Issue