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

On Jul 23, 2017 1:56 PM, "MRAB" <python@mrabarnett.plus.com> wrote: On 2017-07-23 17:08, Todd wrote: probably be something like ntuple(...). Not exactly a literal in that case. If this is true, why not simply add keyword arguments to tuple(...)? Something like (a=1, b=2, c=3) makes very clear sense to me, or even (1, 2, c=3), where the first two are accessible by index only. Or even (1, 2, c: 3), which reminds me of Elixir's expansion of tuple and list keywords. A tuple is a tuple is a tuple. No types. Just convenient accessors. -- C Anthony

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. Steve

On Sun, Jul 23, 2017 at 8:54 PM, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
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

C Anthony Risinger writes:
OK, so I took your "a tuple is a tuple is a tuple" incorrectly. What you want (as I understand it now) is not what def ntuple0(attr_list): return namedtuple("_", attr_list) gives you, but something like what def ntuple1(attr_list) return namedtuple("ImplicitNamedtuple_" + "_".join(attr_list), attr_list) does. Then this would truly be a "duck-typed namedtuple" as Chris Barker proposed in response to Steven d'Aprano elsewhere in this thread. See also Nick's full, namedtuple-compatible, implementation. Of course we still have the horrible "list of strings naming attributes" argument, so you still want a literal if possible, but with a **key argument, a new builtin would do the trick for me. YMMV. -- Associate Professor Division of Policy and Planning Science http://turnbull/sk.tsukuba.ac.jp/ Faculty of Systems and Information Email: turnbull@sk.tsukuba.ac.jp University of Tsukuba Tel: 029-853-5175 Tennodai 1-1-1, Tsukuba 305-8573 JAPAN

Steven, (short of time here) With **kwargs and a little more work, the function would check if the type is already defined, and retur the ntuple with the correct type, not the type. Your sketch of a solution convinced me it can be done with a library function; no additional syntax needed. Cheers, On Tue, Jul 25, 2017 at 5:08 AM, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
-- Juancarlo *Añez*

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. Steve

On Sun, Jul 23, 2017 at 8:54 PM, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
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

C Anthony Risinger writes:
OK, so I took your "a tuple is a tuple is a tuple" incorrectly. What you want (as I understand it now) is not what def ntuple0(attr_list): return namedtuple("_", attr_list) gives you, but something like what def ntuple1(attr_list) return namedtuple("ImplicitNamedtuple_" + "_".join(attr_list), attr_list) does. Then this would truly be a "duck-typed namedtuple" as Chris Barker proposed in response to Steven d'Aprano elsewhere in this thread. See also Nick's full, namedtuple-compatible, implementation. Of course we still have the horrible "list of strings naming attributes" argument, so you still want a literal if possible, but with a **key argument, a new builtin would do the trick for me. YMMV. -- Associate Professor Division of Policy and Planning Science http://turnbull/sk.tsukuba.ac.jp/ Faculty of Systems and Information Email: turnbull@sk.tsukuba.ac.jp University of Tsukuba Tel: 029-853-5175 Tennodai 1-1-1, Tsukuba 305-8573 JAPAN

Steven, (short of time here) With **kwargs and a little more work, the function would check if the type is already defined, and retur the ntuple with the correct type, not the type. Your sketch of a solution convinced me it can be done with a library function; no additional syntax needed. Cheers, On Tue, Jul 25, 2017 at 5:08 AM, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
-- Juancarlo *Añez*
participants (3)
-
C Anthony Risinger
-
Juancarlo Añez
-
Stephen J. Turnbull