Hi All

SUMMARY
This is a longish post. It looks at the idea in general terms, and outlines a way to get the desired semantics (by not syntax) with Python as it is today. And this would be forward compatible with the new syntax, if provided later.

PRESENT
I like the idea of allowing
>>> d[1, 2, 3, a=4, b=5]
and will explore it further.

>>> f(1, 2, 3, a=4, b=5)
but that only works for the get operation. For set the present behaviour is
>>> f(1, 2, 3, a=4, b=5) = None
SyntaxError: can't assign to function call
and I see no good reason to change that.

Going further, I'd say that allowing both
>>> d[something] = value
>>> value = d[something]
is essential to the difference between f(something) and d[something]. Both are expressions, but only one of them can be assigned to.

The proposal therefore is to retain this essential difference, and remove what the proposer regards as an inessential difference. (And I also regard this as an inessential difference.)

Now let's use this class
class Dummy:
def __getitem__(self, *argv, **kwargs):
return argv, kwargs
to peek into how
>>> value = d[something]
works.

Here goes:
>>> d = Dummy()
>>> d[1]
((1,), {})
>>> d[1, 2]
(((1, 2),), {})
>>> d[:]
((slice(None, None, None),), {})
>>> d['a':'b']
((slice('a', 'b', None),), {})

We see that the interpreter passes to __getitem__ a single positional argument (which is usually called the key). This is another difference between d[something] and f(something).

By the way, the slice syntax items[a:b:c] is so often convenient and widespread, that it's been long enabled in Python. I see no good reason to change that.

FUTURE
Let's proceed. We continue to use d = Dummy(). Given that
>>> key = d[1, 2, 3, a=4, b=5]
is allowed, what should we be able to say about the key. Clearly it should be an instance of a class, and there should be a way of creating such an instance without going via d. Let's call the class K (for key).

It is natural to say that
>>> key_1 = d[1, 2, 3, a=4, b=5]
>>> key_2 = K(1, 2, 3, a=4, b=5)
should define two K objects, that are identical. Once we have designed and implemented the class K, we can achieve many of the benefits of this proposal within existing Python.

Here goes. First syntax.
>>> value = d[K(1, 2, 3, a=4, b=5)]
>>> d[K(1, 2, 3, a=4, b=5)] = value

Next, the implementation of such K-mappings. Here, K.set and K.get decorators will help. Something like (not tested):
class MyMap:
def __getitem__(self, x1, x2, x3, a, b):
pass
where K.adjust_get interfaces between the K-object and the definition of __getitem__.

Aside. Here, not tested, is an implementation of K.adjust_get.
class K:
@staticmethod
def __getitem__(self, k):
return fn(self, *k.argv, **k.kwargs)
return __getitem__

This introduction of K allows collections to be created, that can be used today with the syntax
>>> value = d[K(1, 2, 3, a=4, b=5)]
>>> d[K(1, 2, 3, a=4, b=5)] = value

Further, if the K()-less syntax
>>> value = d[1, 2, 3, a=4, b=5]
>>> d[1, 2, 3, a=4, b=5] = value
is added to Python, the existing K-collections could continue to be used, with only a change to the decorator K.adjust_get (and also of course K.adjust_set).

I think that is enough for now. I hope it helps some of us, sometimes. And does no harm elsewhere.
--
Jonathan