On Wed, Sep 02, 2020 at 12:55:43PM +1200, Greg Ewing wrote:
On 2/09/20 3:44 am, 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)
An alternative is to pass an empty tuple as the index when there are no positional args. That would make the following less of a special case:
I think that will interfere with people who need to choose their own default for the index.
Unifying the behaviour of the getter and the setter only makes sense if you have both; for immutable objects (hence no setter) that need only keyword subscripts, why bother declaring an index you're never going to use when you actually want this signature?
__getitem__(self, *, keyword=default)
Having to declare a positional index parameter I don't want, simply for consistency with a setitem I'm not even using, might be a tad annoying.
Solution: best practice suggests that keyword subscripts should be flagged as keyword-only when possible:
def __getitem__(self, index, *, direction='north')
Note that this will only help if the user looks at and takes careful notice of the signature of the __getitem__ method -- it won't actually prevent them from attempting to do obj[0, 'south'] and won't affect the result if they do.
People who are determined enough to write buggy code will write buggy code no matter what you do.
Depending on what your object subscript is supposed to actually do, there are ways to fix this:
- make the direction mandatory rather than give it a default;
- require that index is only a single value (say, an int) and raise if you receive a tuple (int, string);
but ultimately the caller is responsible for providing good input to the methods they call. If the caller knows enough that the subscript needs a direction, they should know enough to know that it has to be passed as keyword.
We can't expect the interpreter itself to prevent all PEBCAK errors.