This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: typing: Unexpected result with value of instance of class inherited from typing.NamedTuple
Type: behavior Stage: needs patch
Components: Documentation, Library (Lib) Versions: Python 3.7, Python 3.6
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, eric.smith, gvanrossum, levkivskyi, rhettinger, Евгений Махмудов
Priority: normal Keywords:

Created on 2018-03-14 22:24 by Евгений Махмудов, last changed 2022-04-11 14:58 by admin.

Files
File name Uploaded Description Edit
python_test.py Евгений Махмудов, 2018-03-14 22:24 Python unittest
Messages (10)
msg313843 - (view) Author: Евгений Махмудов (Евгений Махмудов) Date: 2018-03-14 22:24
Overwriting of default values not working, and used default value of base class. Unittest file if attachment described a problem.
msg313848 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-03-15 00:32
Thanks Евгений Махмудов for the report!

The crux is this:

class A(NamedTuple):
    value: bool = True

class B(A):
    value: bool = False

B(True).value  # Expected True, but is False
B(True)[0]  # True as expected

If we add NamedTuple to B's bases or make its metaclass NamedTupleMeta, it works as expected.

Introspecting the classes a bit more suggests a cause: the class variable A.value is a <property ...>, but B.value is just False, and adding the extra base class or metaclass corrects this.

Ivan, you can probably tell what's wrong from this.  Maybe it's hard to fix, because NamedTuple doesn't appear in A.__mro__?  (IIRC there was a question about that somewhere recently too?)
msg313916 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-03-15 22:36
Yes, this is because subclassing `typing.NamedTuple` is not an actual subclassing, but is just a syntactic sugar for calling `collections.namedtuple`. A discussion about allowing subclassing/extending named tuples previously appeared in https://github.com/python/typing/issues/427 but was subsequently closed as wontfix. In short, the argument was that we should keep feature set and implementation of named tuples simple/minimalistic, and instead recommend dataclasses for all more complex use cases. Note however, that this decision was never added to the `typing.NamedTuple` documentation. I think it totally makes sense to clarify this in the docs.
msg313918 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-03-15 23:03
I wonder if it's too late to conclude that NamedTuple in this context
should have been a class decorator rather than a base class. With a class
decorator it's more understandable that the effect doesn't automatically
apply to subclasses.
msg313919 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-03-15 23:09
I once thought of building NamedTuple functionality into dataclasses, either as a parameter to @dataclass or as a new decorator. But it didn't get very far.

It would have to return a different class, like NamedTuple does, and this didn't fit in well with the original "keep @dataclass simple" mantra.

It would also be especially confusing with frozen already existing.
msg313920 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-03-15 23:16
I would say it is too late. `typing.NamedTuple` is out there for more than a year and is quite actively used. A search on GitHub shows thousands of files that import `typing.NamedTuple` and a macroscopic fraction of those use it with the class syntax. I think the damage from breaking working code outweighs the potential bugs here. A clear example in the docs that explains how it works would be sufficient I think.

(Also a camel case decorator would look weird.)
msg313925 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-03-16 00:00
Apart from the fact that it's too late, if you had to do it over again,
could it be done as a class decorator?

Anyway, let's keep this issue open but reclassify it as a docs issue.
msg313945 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-03-16 10:56
> Apart from the fact that it's too late, if you had to do it over again,
could it be done as a class decorator?

Yes, this could be done as a decorator which would replace the original class with a named tuple after inspecting `__annotations__` and `__dict__`. (But again, the name would be different, since `@NamedTuple` looks weird to me.)
msg313957 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-03-16 16:45
Would it be worthwhile to show an example of a subclass that overrides or extends  __new__?   

Elsewhere in Python, the usual technique for changing method defaults is for a subclass to override or extend the method in question.  

    class A:
        def somemeth(self, value: bool = True):
            print(value)

    class B(A):
        def somemeth(self, value: bool = False):
            super().somemeth(value)
msg314168 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-03-20 22:04
> Would it be worthwhile to show an example of a subclass that overrides or extends  __new__?

I think yes. I would actually add few examples what could (and maybe also couldn't) be done with named tuples.
History
Date User Action Args
2022-04-11 14:58:58adminsetgithub: 77258
2018-03-20 22:04:40levkivskyisetmessages: + msg314168
2018-03-16 16:45:53rhettingersetnosy: + rhettinger
messages: + msg313957
2018-03-16 10:56:45levkivskyisetnosy: + docs@python
messages: + msg313945

assignee: docs@python
components: + Documentation
stage: needs patch
2018-03-16 00:00:01gvanrossumsetmessages: + msg313925
2018-03-15 23:16:59levkivskyisetmessages: + msg313920
2018-03-15 23:09:35eric.smithsetmessages: + msg313919
2018-03-15 23:03:19gvanrossumsetmessages: + msg313918
2018-03-15 22:36:53levkivskyisetmessages: + msg313916
2018-03-15 01:21:59eric.smithsetnosy: + eric.smith
2018-03-15 00:32:16gvanrossumsetmessages: + msg313848
2018-03-14 23:23:40ned.deilysetnosy: + gvanrossum, levkivskyi
2018-03-14 22:24:50Евгений Махмудовcreate