
On Sat, Sep 26, 2020 at 03:48:42PM -0700, Christopher Barker wrote:
On Fri, Sep 25, 2020 at 11:50 PM Steven D'Aprano <steve@pearwood.info> wrote:
1. We have to pass a sentinel to the setitem dunder if there is no positional index passed.
I still don't follow this logic -- why can't nothing be passed? The dunders either require an index or they don't, would that be just like function calling? So (adapting the example in the PEP:
obj[spam=1, eggs=2] # calls type(obj).__getitem__(obj, spam=1, eggs=2)
This sure seems like the obvious way to handle it.
Christopher, with the greatest respect, it is really demoralising for me to explain this issue something like three, four, maybe five times now (I'm not going to go back and count), including this thread which is specifically about this issue, and then have people seemingly not even read it before writing back to disagree :-( The problem isn't with the `__getindex__` dunder. It's the `__setindex__` dunder. I said it right there in the comment you quoted. Okay, I was lazy and dropped the underscores, but still, **set**index is right there. Then I spent a lot of time explaining why setindex is a problem. The problem is, how does the interpreter pass the second positional argument without passing something as the first positional argument? This isn't a problem for subscripting alone. It's a problem for any function call: def function(first=None, second=None, /): print(first, second) I've explicitly flagged the arguments as "positional only" to avoid (non-)solutions that rely on the interpreter knowing the names of the parameters at runtime. You can only pass arguments by position, they have to be filled left-to-right, and the aim is to successfully pass a value for `second` but no value for `first`. You can't rely on the author of the function to do the argument processing like this: def function(*args): if len(args) == 1: second = args[0] first = None # default elif len(args) == 2: first, second = args else: raise TypeError('wrong number of arguments') That's why there are so few functions in the Python ecosystem with a signature similar to range: range( [start,] end [, step] ) and that's the problem that we solve here by auto-filling some sentinel for the index when the subscript is keyword-only. If the constraints are: * the right hand side assignment value gets bound to the second positional argument (not counting "self"), as expected; * there are no changes to way the interpreter binds arguments to parameters; * there is no requirement that all `__setitem__` methods use the same fixed parameter name for the value argument so that it can be passed by a standard name (even "self" is just a convention); * and no runtime introspection by the interpreter to find out what the parameter name is (too slow); then it is hard to see any other solution than to pass a special sentinel to setitem to represent the missing index. If you have any other solutions, or if you have a persuasive argument in favour of relaxing one or more of those constraints, I'd love to hear it. -- Steve