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
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/KEEC3QI4H5AU754BCYSO75D6NCZ6UETS/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to