
On Sat, Sep 26, 2020 at 07:12:00PM -0400, Ricky Teachey wrote:
Another inconsistency is that the case of keyword arguments only would bind the RHS value to the first positional argument, which is the index, and not the value. I think this is what Guido was referring to when he responded talking about introspection being required? Not sure.
in any case, to me that doesn't seem like such a big deal period it might lead to some weird error messages but I'm not sure why it's such a big problem. Maybe it poses a difficulty for type hinting?
I had a few paragraphs about exactly that scenario in my earlier post, but I deleted it because I didn't think it would be popular. So let me see if I can recreate it from memory. You are suggesting that if there is no positional index, the interpreter should just pack the value into the left-most parameter. Here's the signature of my method: # Round 1 def __setitem__(self, index, value, *, spam=0): and the caller uses this: obj[spam=1] = 99 so 99 gets packed into the index and the exception says something like: TypeError: missing 1 required positional argument: 'value' which is surely going to confuse a lot of people, because the value is clearly 99. It's the index which is missing. Round 2: change the signature. def __setitem__(self, index, value=None, *, spam=0): and now the parameters get packed as index=99 and value=None, so there's no exception, but that looks like `obj[99, spam=1] = None` which would be indistinguishable from a perfectly normal call. Round 3: SENTINEL = object() # Private sentinel value for subscripts. # Or maybe use NotImplemented? def __setitem__(self, index, value=SENTINEL, *, spam=0): if value is SENTINEL: value = index index = SENTINEL # or raise if index is SENTINEL: # Handle keywords with no index else: # Handle index + keywords and now we have something usable. That's not a lot of boilerplate code, but if you don't write it, you get a weirdly misleading error message, as in Round 1 above. Ultimately I think it's going to be up to the PEP authors to decide what they want to propose here. I think we now have these choices: 1. Fill in a default index with one of: a. None b. empty tuple () c. NotImplemented d. a new, unhashable builtin Missing or NoIndex 2. Prohibit keyword-only subscripts. 3. Bind the right-hand side value to the index parameter, and leave the value parameter blank (as above). Did I miss any? There are probably more heavyweight alternatives that require changes to parameter binding, or new dunders, or runtime introspection of the dunder, but I'm not sure that the PEP authors want to consider those (and if they do, they should probably be in a competing PEP). I think that: 1a. is difficult (but not impossible) for numpy to use; 1b. makes a certain sense but is confusable with an actual tuple subscript; 1c. recycles an existing builtin that is very unlikely to be currently used as a subscript; 1d. avoids any chance of that, but requires a new builtin; 2. would be disappointing but I could live with it; 3. feels ugly and inelegant and will probably confuse people. Stefano, Jonathan, I think that if there's no more comments on this specific issue in the next few days, it's up to you now to make a choice, put it in the PEP, list the alternatives as above and why you are rejecting them (perhaps by linking to this thread -- you don't have to recap the entire discussion inside the PEP, just a brief summary). -- Steve