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: Add ** Map Unpacking Support for namedtuple
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: John Crawford, jcrotts, rhettinger, serhiy.storchaka
Priority: normal Keywords:

Created on 2018-02-15 18:10 by John Crawford, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (7)
msg312218 - (view) Author: John Crawford (John Crawford) Date: 2018-02-15 18:10
At present, `collections.namedtuple` does not support `**` map unpacking despite being a mapping style data structure.  For example:

    >>> from collections import namedtuple
    >>> A = namedtuple("A", "a b c")
    >>> a = A(10, 20, 30)
    >>> def t(*args, **kwargs):
    ...     print(f'args={args!r}, kwargs={kwargs!r}')
    ...
    >>> t(*a)
    args=(10, 20, 30), kwargs={}
    >>> t(**a)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: t() argument after ** must be a mapping, not A
    >>> 

No doubt, the lack of current support is due to namespace conflicts that result from trying to provide a `keys` method amidst also supporting attribute-style access to the `namedtuple` class.  As we can see, providing a `keys` attribute in the `namedtuple` produces an interesting result:

    >>> Record = namedtuple("Record", "title keys description")
    >>> t(**Record(1, 2, 3))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: attribute of type 'int' is not callable
    >>>

To me, this calls out a design flaw in the `**` unpacking operator where it depends on a method that uses a non-system naming convention.  It would make far more sense for the `**` operator to utilize a `__keys__` method rather than the current `keys` method.  After all, the `__<methodname>__` naming convention was introduced to avoid namespace conflict problems like this one.
msg312219 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-02-15 18:52
The intended way to support **unpacking is the _asdict() method:

    t(**a._asdict())

It doesn't really make sense to add direct support for **unpacking because named tuples are sequences and not mappings.  To support **unpacking, we would have to add a keys() method and modify __getitem__() to handle both integer indexing and string key lookup.  Once we have **a and a[k] and a.keys(), people would also want a.values() a.items() etc.  The world gets murky when both sequence and mapping behaviors become commingled.
msg312220 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-02-15 19:26
Concur with Raymond.
msg312252 - (view) Author: Jay Crotts (jcrotts) * Date: 2018-02-16 20:41
Would it be worth adding an example of unpacking such as, t(**a._asdict()), or something similar to the documentation ?
msg312276 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2018-02-17 08:13
> Would it be worth adding an example of unpacking such as,
> t(**a._asdict()), or something similar to the documentation ?

There are a myriad of uses for dictionaries and the namedtuple docs don't seem like to right place to cover them (**unpacking, str.format_map, str.__mod__, etc).  Even the dict and OrderedDict docs don't cover these.

Also, the use of somefunc(**nt._asdict()) isn't a common pattern.  A requirement for **unpacking tends to nudge design choices towards an actual mapping rather than a tuple or tuple subclass for the underlying data store.  That is likely why this hasn't come-up before.
msg312277 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-02-17 08:42
I wandering if it is worth to add a general function that takes an object and a sequence of keys and return a mapping proxy that maps attribute names to values.
msg312359 - (view) Author: Jay Crotts (jcrotts) * Date: 2018-02-19 18:33
Thanks Raymond, I wasn't sure if it was a common pattern or not, that makes sense.
History
Date User Action Args
2022-04-11 14:58:57adminsetgithub: 77035
2018-03-04 21:50:45serhiy.storchakasetstatus: open -> closed
resolution: rejected
stage: resolved
2018-02-19 18:33:31jcrottssetmessages: + msg312359
2018-02-17 08:42:37serhiy.storchakasetmessages: + msg312277
2018-02-17 08:13:55rhettingersetmessages: + msg312276
2018-02-16 20:41:34jcrottssetnosy: + jcrotts
messages: + msg312252
2018-02-15 19:26:25serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg312220
2018-02-15 18:52:50rhettingersetnosy: + rhettinger
messages: + msg312219
2018-02-15 18:10:32John Crawfordcreate