On Fri, Aug 14, 2020 at 3:05 AM Jonathan Fine <jfine2358@gmail.com> wrote:
I'd like to sound out consensus regarding mapping access, where none of the keys are positional. In particular, I suggest that PEP 472 allow syntax and semantics such as
    >>> d[x=1, y=2] = 42
    >>> d[x=1, y=2]
and ask whether the class
    >>> X = type(d)
should be part of standard Python.

This way of phrasing it rubs me the wrong way. The way Python is defined, notations like `x+y` or `a[i]` translate to dunder calls and we separately specify which built-in types support which dunder methods. If you think `dict` should support the extended subscript notation, just say so, don't play guessing games with `X = type(d)`. (You've given the answer away by naming the variable `d` anyway.)

Personally I think `dict` should *not* support the extended subscript notation, but I think the extended `__getitem__` protocol should support passing just keyword args.
At present, item access requires an argument, as a matter of syntax.
    >>> d[]
    SyntaxError: invalid syntax

Compare this to
    >>> fn()
    NameError: name 'fn' is not defined

I'd like d[] to become valid syntax.

This looks like a syntax error that would trip over a lot of people. I guess we could make it less dangerous if common types like `dict` rejected this at runtime. But if you insist that `dict` should support keyword args, I would personally insist on making this syntax illegal.
I can see two basic ways of allowing no arguments. One is for the interpreter to construct an object that is the argument passed to __getitem__ and so forth. The other is to not pass an argument at all. I see this as a secondary question.

The signatures could be
def __getitem__(self, index=default, /, **kwargs): ...
def __setitem__(self, index=default, value, /, **kwargs): ...
A class that doesn't want to support `a[]` would indicate so by not providing a default index, and then it would simply raise a TypeError, just like calling a function with a missing required argument.
I'd like
    >>> d[x=1, y=2]
to be valid syntax. It's not clear to me that all agree with this. Even if there are no objections, I'd like positive confirmation.

Both Greg Ewing and Steven D'Aprano agree with this, and it looks fine to me as well, so I think you've got this.
   >>> d[x=1, y=2]
is valid syntax. If so, then there is I think consensus that
    >>> d[x=1, y=2] = 42
    >>> d[x=1, y=2]
can be implemented, where d is an instance of a suitable class. Otherwise, what's the point?

Yes of course. A MutableMapping subclass that wanted to do this could be defined like this:
class KeyKey(MutableMapping):

    def __getitem__(self, key=None, /, **kwds):
        return super().__getitem__(self.makekey(key, kwds))

    def __setitem__(self, key=None, value, /, **kwds):
        return super().__setitem__(self.makekey(key, kwds), value)

    def makekey(self, key, kwds):
        return (key, tuple(sorted(kwds)))  # Or something more sophisticated
(A few other methods would have to be added, like `__delitem__` and `__contains__`; the caller of `__contains__` would need to know about the makekey() method.)
Suppose we have
    >>> d[x=1, y=2] = 42
    >>> d[x=1, y=2]
where d is an instance of a suitable class X that has no special knowledge of keywords.

Why should X not be required to have knowledge of keywords?
In other words, we also have for example
    >>> d[a='alpha', g='gamma', z=12] = 'cheese'
    >>> d[a='alpha', g='gamma', z=12]

My question is this: Should such a class
   >>> X = type(d)
be part of standard Python, as part of PEP 472? (My answer is: Yes, it should be in standard Python.)

At this time, I'm interested in canvassing opinions. Discussion of different opinions perhaps can take place later, or elsewhere. My main concern is to know if there is at present a rough consensus regarding the above.

I don't think you have consensus at all -- in fact I haven't seen anyone besides you agreeing that `d[x=1, y=2]` should construct a key of a special type and pass that to `__getitem__` -- everyone else (including myself) appears to think that it's better to pass the keyword args to `__getitem__` and decide the edge cases based on that.

FWIW in my example I sorted the keywords, so that `d[x=1, y=2]` and `d[y=2, x=1]` construct the same internal key. But for some use cases it might be better if these constructed *different* internal keys. For example, Caleb's Struct class, when used to construct a dataclass, would need to be able to tell them apart, since the field order in a dataclass is part of the type -- the argument order of the constructor depends on it.
--Guido van Rossum (python.org/~guido)