[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