On Wed, Aug 26, 2020 at 11:19 AM Steven D'Aprano <st...@pearwood.info>
wrote:

> On Wed, Aug 26, 2020 at 10:10:34AM -0400, Ricky Teachey wrote:
>
> > But I have to say that I think this latest is a fantastic idea, and when
> > Jonathan presented it to me it was very surprising that I had not seen it
> > presented by anyone else yet. I think it solves a ton of problems,
>
> Such as?
>

It creates a language supported way for the creator of the class to decide
how to interpret the contents inside a subscript operation. This is a
problem because disagreement over this matter is a large part of the reason
PEP 472-- the spirit of which I support-- has been held up. It greatly
alleviates (though not perfectly-- see the end of this message) the
incongruity between how the indexing operator behaves and function calls
behave. As explained by Jonathan Fine, it adds flexibility and smoothes out
the differences the different paradigms of subscript operations: sequences,
and mappings. And it opens up opportunities for other paradigms to be
created, the most prominent example of which is type-hint creation
shortcuts, like:

Vector = Dict[i=float, j=float]

> adds a huge amount of flexibility and functionality,
>
> Such as?
>
> With the proposal, the language would support any function desired to turn
> > the "stuff" inside a subscripting operation into the item dunder calls.
>
> I'm sorry, I don't understand that sentence.
>

I'll provide examples.


> > For example: if this proposal were already in place and PEP 472 were to
> > continue to be held up because of terrorists like me ;) *, one could have
> > written this translation function and PEP-472-ify their classes already:
> >
> > def yay_kwargs(self, *args, **kwargs):
> >     return self.__getitem__(args, **kwargs)
>
> You're calling the `__getitem__` dunder with arbitrary keyword
> arguments. Are you the same Ricky Teachey who just suggested that we
> should be free to break code that uses `__getitem__` methods that don't
> obey the intent that they have only a single parameter and no keywords?
>

I am talking hypothetically-- if this proposal were already in place (which
*includes* passing kwargs to the *new dunder* rather than passing them to
the existing item dunders by default), you could write code like yay_kwargs
today, even if the default way the language behaves did not change.

In that universe, if I wrote this:

class C:
    def __getitem__(self, key):
        print(key)

...and tried to do this:

>>> C()[a=1]
SomeError

...*in that universe*, without PEP 472, the language will STILL, by
default, give an error as it does today (though it probably would no longer
be a SyntaxError).

PEP 472 is a proposal to change *the current, default key or index
translation function* to pass **kwargs. *This *proposal is to allow for an
intervening function that controls HOW they are passed.

If PEP 472 is held up, then `obj[1, 2, axis='north']` is a SyntaxError,
> so how does this method yay_kwargs make it legal?
>
>
>
> --
> Steve
>

Because the proposal is that if there is a dunder present containing the
class attribute function, the contents of the [ ] operator get passed to
that function for translation into the key.

We could make the dunder to accept the target dunder method name as a
parameter. This way there is only a single new dunder, rather than 3.

The single new dunder might look like this:

class Q:
    def __subscript__(self, method_name, *args, **kwargs):
         return getattr(self,  method_name)(*args, **kwargs)
    def __getitem__(self, *args, **kwargs): ...
    #  Note that I have made the RHS value the first argument in __setitem__
    def __setitem__(self, value, *args, **kwargs): ...
    def __delitem__(self, *args, **kwargs): ...

Above I am calling the appropriate dunder method directly inside of
__subscript__. Again, there are other ways to do it and it does not have to
be this way.

If it is done that way, the  __subscript__ dunder gets passed which item
dunder method is being called (__getitem__, __setitem__, or __delitem__),
and the arguments. Examples:

No  CODE            CALLS
1.    q[1]                 q.__subscript__("__getitem__", 1)
2.    q[1,]                q.__subscript__("__getitem__", 1)
3.    q[(1,)]              q.__subscript__("__getitem__", 1)
4.    q[(1,),]             q.__subscript__("__getitem__", (1,))
5.    q[1] = 2           q.__subscript__("__setitem__", 2, 1)
6.    q[1,] = 2          q.__subscript__("__setitem__", 2, 1)
7.    q[(1,)] = 2        q.__subscript__("__setitem__", 2, 1)
8.    q[(1,),] = 2       q.__subscript__("__setitem__", 2, (1,))

And so on for the __delitem__ calls.

NOTE: #3 and #7 are very unfortunate, but we cannot change this without
breaking backwards compatibility.

---
Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home
or actually going home." - Happy Chandler
_______________________________________________
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/RO5BMWMEU3V7MXOJXZYM56AAM2CMWHTO/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to