-
Notifications
You must be signed in to change notification settings - Fork 258
namedtuple: add defaults to the Python 3.6 syntax #338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This lets you write: class Employee(NamedTuple): name: str id: int language: str = 'python' as suggested by Guido on python-ideas.
How does it work? Would this be valid:
|
@ruxi Yes, that syntax already works in Python 3.5. Python 3.6's variable annotation syntax makes it possible to instead create typed NamedTuples using subclassing, like:
This pull request extends that syntax to use the values of variables assigned in the class body as default values. |
Let's wait until after Python 3.6.0 and 3.5.3 are released. I don't want to
rock the release boat any more than necessary.
|
(But apart from my desire to delay merging, it's beautiful! Now of course we need support for mypy too...) |
@@ -1916,7 +1916,21 @@ def __new__(cls, typename, bases, ns): | |||
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()) | |||
saw_default = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think saw_default
is redundant. You could use elif defaults:
or elif defaults_dict:
, instead of elif saw_default:
below.
defaults.append(default_value) | ||
defaults_dict[field_name] = default_value | ||
elif saw_default: | ||
raise TypeError('Non-default namedtuple field cannot follow default field') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be sometimes helpful to mention which fields are conflicting, for example f'Non-default namedtuple field {field_name} cannot follow default fields {list(defaults_dict.keys())}'
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, but I guess we can't use an f-string because this code has to be syntactically valid in older Python 3.
defaults_dict[field_name] = default_value | ||
elif saw_default: | ||
raise TypeError('Non-default namedtuple field cannot follow default field') | ||
nm_tpl.__new__.__defaults__ = tuple(defaults) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also probably you could use only defaults_dict
and then write here = tuple(defaults_dict.values())
, since dict
is ordered in Python 3.6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand it, dict ordering is an implementation detail of CPython 3.6 and a conforming Python 3.6 implementation could choose to not implement ordering, so this code shouldn't rely on dict ordering (except for class namespaces and **kwargs because of PEP 520 and PEP 468).
@JelleZijlstra Thank you! |
…variable Thanks Ivan for reviewing!
I'm okay with this idea. @ilevkivskyi Is it good from your POV? We also need a mypy implementation, and docs for Python. |
I like the idea. The mypy implementation should not be difficult, but it is not high on my priority list (I will make PRs for several other mypy issues soon). |
Although I would prefer this PR to be merged without waiting for mypy support, to avoid possible conflicts with #352. |
Thanks! I'll work on implementing this in mypy as soon as I finish implementing async generators and will add a doc patch to CPython once this is merged. |
OK, I'll leave it to @ilevkivskyi to make sure all the parts land. |
Also merged this to CPython. (Note: we need a Misc/NEWS item for the various typing.py changes.) |
Thanks! Created http://bugs.python.org/issue29310 to track documenting this in CPython. |
This implements python/typing#338 in mypy.
This lets you write:
as suggested by @gvanrossum on python-ideas.
Should I also add this to any relevant documentation? I imagine mypy will also need changes to support this syntax.