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/