
On 01.09.20 17:44, Steven D'Aprano wrote:
(9) Keyword-only subscripts are permitted:
obj[spam=1, eggs=2] # calls type(obj).__getitem__(spam=1, eggs=2)
del obj[spam=1, eggs=2] # calls type(obj).__delitem__(spam=1, eggs=2)
but note that the setter is awkward since the signature requires the first parameter:
obj[spam=1, eggs=2] = value # wants to call type(obj).__setitem__(???, value, spam=1, eggs=2)
Proposed solution: this is a runtime error unless the setitem method gives the first parameter a default, e.g.:
def __setitem__(self, index=None, value=None, **kwargs)
Note that the second parameter will always be present, nevertheless, to satisfy the interpreter, it too will require a default value.
(Editorial comment: this is undoubtably an awkward and ugly corner case, but I am reluctant to prohibit keyword-only assignment.)
Why does the signature require the first `index` parameter? When I see `obj[spam=1, eggs=2] = value` there's no positional index and so I wouldn't expect one to be passed. Similar to how the following works: >>> def foo(): ... pass ... >>> foo(*()) If there's nothing to unpack nothing will be assigned to any of the parameters. So the following signature would work with keyword-only subscripts: def __setitem__(self, value, **kwargs): I don't how the `[] =` operator is translated to `__setitem__` at the implementation level, so perhaps the no-positional-index case would require yet another opcode, but thinking of it in the following way it would definitely be possible: obj.__setitem__(*(pos_index + (value,)), **kwargs) where `pos_index` is the positional index collected from the `[]` operator as a tuple (and if no such index is given it defaults to the empty tuple). This matches the above no-index signature of `__setitem__`. This is also the signature of the corresponding `__getitem__` and `__delitem__` methods.