On Fri, Jul 17, 2020 at 11:11:17AM -0400, Ricky Teachey wrote:
It seems to me that the validity of this key-object paradigm is directly tied to the decision of whether or not to change the get/set item dunder signatures.
But note that even if we allow keyword args in subscripts, we still don't have to change the signatures of existing objects. If keyword args aren't meaningful to a specific class, it will just change from a SyntaxError to a runtime TypeError.
*If it turns out* the desired way forward is to not change the signature for __getitem__ and __setitem__, only then does a key object exists. If not, I suggest it means the key-object does not exist.
On the other hand, if it were determined we'd rather have **kwargs become part of these signatures, there is no "key object". There is more of an unpacked kwargs, or unpacked namespace, object.
So it isn't obvious to me that this object *must be* some key object. It certainly CAN be. But the syntax looks so much like kwargs being supplied to a function, a (currently ephemeral) namespace object, or unpacked kwargs object, might be more of a valid way to think about it:
Indeed. And we need not require the method to unpack a kwargs dict themselves. We can allow (but not require!) keyword parameters in the method signature. Now the interpreter will handle the hard work of matching up keyword arguments to parameters. class MyClass: def __getitem__(self, item=None, *, x, y=0, **kw): # requires keyword arg x # optional keyword arg y # permits any other arbitrary keyword args instance = MyClass() instance[2:3, x=1, y=2, z=3] # receives arguments item=slice(2, 3), x=1, y=2, kw={'z': 3} For backwards-compatibility, there will only ever be a single positional argument passed into the method. That's because comma-separated values in a subscript are already passed as a tuple: # this calls __getitem__ with a single tuple argument obj[a,b:c,d] ==> (1, slice(2, 3), 4) So that's not going to change (at least not without a long and painful deprecation process). But adding support for keyword arguments requires no changes to any existing class or a new builtin "key object" type.
But! On the other hand, the huge difference here is that currently, the signature of the get/set item dunders only accepts a single key argument.
To be precise, you can put any signature you like into a `__getitem__` method, but only the first positional argument will be called from subscripting syntax. py> class Demo: ... def __getitem__(self, item, more=None, *args, x=0, y=1, **kw): ... return (item, more, args, x, y, kw) ... py> Demo()['item'] ('item', None, (), 0, 1, {}) Even if you pass comma-separated values, including slices, they all get packed into a tuple and passed as the first parameter `item`. But there is no need to emulate that for keyword args. They can, and I think should, simply be unpacked into keyword parameters exactly the same as function call syntax does. If, by chance, some class wants Jonathan's "keyword object" semantics, it's easy to get: def __getitem__(self, **kwargs): All the keyword arguments will be handed to you as a dict. You can then convert it to whatever special keyword object that suits your purposes. -- Steven