[Python-ideas] namedtuple literals [Was: RE a new namedtuple]

Nick Coghlan ncoghlan at gmail.com
Mon Jul 31 01:38:26 EDT 2017

On 31 July 2017 at 04:31, Paul Moore <p.f.moore at gmail.com> wrote:
> On 30 July 2017 at 16:24, Nick Coghlan <ncoghlan at gmail.com> wrote:
>> Rather than being about any changes on that front, these threads are
>> mostly about making it possible to write that first line as:
>>     MyNT = type(implicitly_typed_named_tuple_factory(foo=None, bar=None))
> Is that really true, though? There's a lot of discussion about whether
> ntuple(x=1, y=2) and ntuple(y=2, x=1) are equal (which implies they
> are the same type).

No, they're different types, because the requested field order is
different, just as if you made two separate calls to
"collections.namedtuple". If you want them to be the same type, so
that the parameter order in the second call gets ignored, then you
need to ask for that explicitly (either by using
"collections.namedtuple" directly, or by calling type() on an
implicitly typed instance), or else by keeping the field order

> If there's any way they can be the same type, then
> your definition of MyNT above is inherently ambiguous, depending on
> whether we've previously referred to
> implicitly_typed_named_tuple_factory(bar=None, foo=None).

This is why any implicit type definition would *have* to use the field
order as given: anything else opens up the opportunity for
action-at-a-distance that changes the field order based on the order
in which instances are created. (Even without that concern, you'd also
get a problematic combinatorial expansion when searching for matching
existing field definitions as the number of field names increases)

> For me, the showstopper with regard to this whole discussion about
> ntuple(x=1, y=2) is this key point - every proposed behaviour has
> turned out to be surprising to someone (and not just in a "hmm, that's
> odd" sense, but rather in the sense that it'd almost certainly result
> in bugs as a result of misunderstood behaviour).

I suspect the only way it would make sense is if the addition was made
in tandem with a requirement that the builtin dictionary type be
insertion ordered by default.

The reason I say that is that given such a rule, it would
*consistently* be true that:

    tuple(dict(x=1, y=2).items()) != tuple(dict(y=2, y=1).items())

Just as this is already reliably true in Python 3.6 today:

    >>> from collections import OrderedDict
    >>> x_first = tuple(OrderedDict(x=1, y=2).items())
    >>> y_first = tuple(OrderedDict(y=2, x=1).items())
    >>> x_first != y_first
    >>> x_first
    (('x', 1), ('y', 2))
    >>> y_first
    (('y', 2), ('x', 1))

In both PyPy and CPython 3.6+, that's actually true for the builtin
dict as well (since their builtin implementations are order preserving
and that's now a requirement for keyword argument and class execution
namespace handling).

That way, the invariant that folks would need to learn would just be:

    ntuple(x=1, y=2) == tuple(dict(x=1, y=2).values())
    ntuple(y=2, x=1) == tuple(dict(y=2, x=1).values())

rather than the current:

    from collections import OrderedDict
    auto_ntuple(x=1, y=2) == tuple(OrderedDict(x=1, y=2).values())
    auto_ntuple(y=2, x=1) == tuple(OrderedDict(y=2, x=1).values())

(Using Python 3.6 and auto_ntuple from


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

More information about the Python-ideas mailing list