[Python-ideas] a new namedtuple

Nick Coghlan ncoghlan at gmail.com
Tue Jul 18 09:29:47 EDT 2017


On 18 July 2017 at 14:31, Guido van Rossum <guido at python.org> wrote:
> On Mon, Jul 17, 2017 at 6:25 PM, Eric Snow <ericsnowcurrently at gmail.com>
> wrote:
>>
>> On Mon, Jul 17, 2017 at 6:01 PM, Ethan Furman <ethan at stoneleaf.us> wrote:
>> > Guido has decreed that namedtuple shall be reimplemented with speed in
>> > mind.
>>
>> FWIW, I'm sure that any changes to namedtuple will be kept as minimal
>> as possible.  Changes would be limited to the underlying
>> implementation, and would not include the namedtuple() signature, or
>> using metaclasses, etc.  However, I don't presume to speak for Guido
>> or Raymond. :)
>
>
> Indeed. I referred people here for discussion of ideas like this:
>
>>>> a = (x=1, y=0)

In that vein, something I'll note that *wasn't* historically possible
due to the lack of keyword argument order preservation is an
implementation that implicitly defines anonymous named tuple types
based on the received keyword arguments.

Given Python 3.6+ though, this works:

    from collections import namedtuple

    def _make_named_tuple(*fields):
        cls_name = "_ntuple_" + "_".join(fields)
        # Use the module globals as a cache for pickle compatibility
        namespace = globals()
        try:
            return namespace[cls_name]
        except KeyError:
            cls = namedtuple(cls_name, fields)
            return namespace.setdefault(cls_name, cls)

    def ntuple(**items):
        cls = _make_named_tuple(*items)
        return cls(*items.values())

    >>> p1 = ntuple(x=1, y=2)
    >>> p2 = ntuple(x=4, y=5)
    >>> type(p1) is type(p2)
    True
    >>> type(p1)
    <class '__main__.ntuple_x_y'>

That particular approach isn't *entirely* pickle friendly (since
unpickling will still fail if a suitable type hasn't been defined in
the destination process yet), but you can fix that by way of playing
games with setting cls.__qualname__ to refer to an instance of a
custom class that splits "_ntuple_*" back out into the component field
names in __getattr__ and then calls _make_named_tuple, rather than
relying solely on a factory function as I have done here.

However, it also isn't all that hard to imagine a literal syntax
instead using a dedicated builtin type factory (perhaps based on
structseq) that implicitly produced types that knew to rely on the
appropriate builtin to handle instance creation on unpickling - the
hardest part of the problem (preserving the keyword argument order)
was already addressed in 3.6.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list