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

C Anthony Risinger c at anthonyrisinger.com
Mon Jul 24 13:13:01 EDT 2017

On Sun, Jul 23, 2017 at 8:54 PM, Stephen J. Turnbull <
turnbull.stephen.fw at u.tsukuba.ac.jp> wrote:

> C Anthony Risinger writes:
>  > A tuple is a tuple is a tuple. No types. Just convenient accessors.
> That's not possible, though.  A *tuple* is an immutable collection
> indexed by the natural numbers, which is useful to define as a single
> type precisely because the natural numbers are the canonical
> abstraction of "sequence".  You can use the venerable idiom
> X = 0
> Y = 1
> point = (1.0, 1.0)
> x = point[X]
> to give the tuple "named attributes", restricting the names to Python
> identifiers.  Of course this lacks the "namespace" aspect of
> namedtuple, where ".x" has the interpretation of "[0]" only in the
> context of a namedtuple with an ".x" attribute.  But this is truly an
> untyped tuple-with-named-attributes.
> However, once you attach specific names to particular indexes, you
> have a type.  The same attribute identifiers may be reused to
> correspond to different indexes to represent a different "convenience
> type".  Since we need to be able to pass these objects to functions,
> pickle them, etc, that information has to be kept in the object
> somewhere, either directly (losing the space efficiency of tuples) or
> indirectly in a class-like structure.
> I see the convenience of the unnamed-type-typed tuple, but as that
> phrase suggests, I think it's fundamentally incoherent, a high price
> to pay for a small amount of convenience.
> Note that this is not an objection to a forgetful syntax that creates
> a namedtuple subtype but doesn't bother to record the type name
> explicitly in the program.  In fact, we already have that:
>     >>> from collections import namedtuple
>     >>> a = namedtuple('_', ['x', 'y'])(0,1)
>     >>> b = namedtuple('_', ['x', 'y'])(0,1)
>     >>> a == b
>     True
>     >>> c = namedtuple('_', ['a', 'b'])(0,1)
> This even gives you free equality as I suppose you want it:
>     >>> a == c
>     True
>     >>> a.x == c.a
>     True
>     >>> a.a == c.x
>     Traceback (most recent call last):
>       File "<stdin>", line 1, in <module>
>     AttributeError: '_' object has no attribute 'a'
>     >>> c.x == a.a
>     Traceback (most recent call last):
>       File "<stdin>", line 1, in <module>
>     AttributeError: '_' object has no attribute 'x'
> Bizarre errors are the inevitable price to pay for this kind of abuse,
> of course.
> I'm not a fan of syntaxes like "(x=0, y=1)" or "(x:0, y:1)", but I'll
> leave it up to others to decide how to abbreviate the abominably ugly
> notation I used.

Sure sure, this all makes sense, and I agree you can't get the accessors
without storing information, somewhere, that links indexes to attributes,
and it makes complete sense it might be implemented as a subtype, just like
namedtuple works today.

I was more commenting on what it conceptually means to have the designation
"literal". It seems surprising to me that one literal has a different type
from another literal with the same construction syntax. If underneath the
hood it's technically a different type stored in some cached and hidden
lookup table, so be it, but on the surface I think most just want a basic
container with simpler named indexes.

Every time I've used namedtuples, I've thought it more of a chore to pick a
name for it, because it's only semi-useful to me in reprs, and I simply
don't care about the type, ever. I only care about the shape for comparison
with other tuples. If I want typed comparisons I can always just use a
class. I'd also be perfectly fine with storing the "type" as a field on the
tuple itself, because it's just a value container, and that's all I'll ever
want from it.

Alas, when I think I want a namedtuple, I usually end up using a dict
subclass that assigns `self.__dict__ = self` within __new__, because this
makes attribute access (and assignment) work automagically, and I care
about that more than order (though it can be made to support both).

At the end of the day, I don't see a way to have both a literal and
something that is externally "named", because the only ways to pass the
name I can imagine would make it look like a value within the container
itself (such as using a literal string for the first item), unless even
more new syntax was added.


C Anthony
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20170724/992e9e8d/attachment-0001.html>

More information about the Python-ideas mailing list