On Sun, Aug 30, 2020 at 11:33 PM Christopher Barker <pythonchb@gmail.com> wrote:
I *think* the trailing comma is shorthand for a larger class of problems. That is, in the current system, you can only put a single expression in the [], so a comma creates a tuple. Which means that:

i = (a,)
thing[i] = x

is the same as:
thing[a,] = x

and 
i = (a, b, c)
thing[i] = x
is the same as:
thing[a, b, c] = x

etc ....

It's not *quite* so simple (though almost so). The parser still treats it specially, because the slice notation `a:b`, `a:b:c`, (and degenerate forms like `:` or `::`) are only allowed at the top level. That is, `d[::]` is syntactically valid, but `d[(::)]` is not. Try it.
 
And I don't think, when the interpreter sees  a comma inside a [], there is any way to know whether the user explicitly wanted a tuple, or wanted to express multiple indexes. I suppose we could assume that a single comma was not intended to be a tuple, but maybe it was?

In the current system nobody has ever had to think about that. A single comma most definitely makes a tuple.
 
THe real challenge here is that I suspect most users don't realize that when you do, e.g. arr[i, j] in numpy, you are passing a tuple of two indexes, rather than two separate values. Conversely, when you do, e.g. a_dict[(a,b,c)] that you could hve omited the brackets and gotten the same result.

These are all mindgames.

What your intention is depends on what kind of data structure it is (e.g dicts have a one-dimensional key set, but keys may be tuples, whereas numpy arrays have any number of dimensions, but each dimension is numeric). How what you write is interpreted is entirely up to the `__getitem__` and `__setitem__` implementation of the data structure you are using. Those methods must be written to handle edge cases according to their intended model (I'm sure there's lots of code in e.g. numpy and Pandas to handle the special case where the "key" argument is not a tuple.)

The protocol is what it is and you can use it in different ways, as long as you follow the protocol.
 
but in current Python, it doesn't matter that folks don't realize that, as you can in fact only put one expression in there, and the tuple creating ends up being an implementation detail for most users.'

(Technically not so, because of the slices. Note that dict doesn't even check for slices -- they fail because they're unhashable. But you can write `d[...] = 1` and now you have `Ellipsis` as a key.)

But once we add keyword arguments, then it will look a LOT more like function call, and then folks will expect it to behave like a function call, where thing(a, b) and thing((a,b)) are not, in fact the same -- but I don't think there is any way to meet that expectation without breaking existing code.

I think it's up to the implementers of extended `__getitem__` and `__setitem__` methods to set the right expectations **for their specific data type**.
 
However, if we keep it like it is, only adding keywords, but not changing anything about how the "positional" arguments are handled, then we have backward compatibility, and naive users will only notice (maybe) that you can't do `*args`. Which is not that big a deal -- all you have to say, really is that tuple unpacking isn't allowed in indexing. Done. Anyone that wants to know *why* not can do more research.

Right.
 
Key point: as a rule, classes that handle keyword indexes (e.g. xarray and the like) will be written by a small number of people, and used by many more -- and the authors of such classes are by definition more experienced in general. So the priority has to be to keep things as simple as possible for users of such classes.

Which leads to what design choices?

I think we need to watch out that we're not trying to make `a[1, 2, k=3]` look like a function call with funny brackets. It is a subscript operation with keyword parameters. But it is still first and foremost a subscript operation.

And yeah, backwards compatibility is a b****.

--
--Guido van Rossum (python.org/~guido)