On Fri, Sep 25, 2020 at 11:50 PM Steven D'Aprano <[email protected]>
wrote:
> TL;DR:
>
> 1. We have to pass a sentinel to the setitem dunder if there is no
> positional index passed. What should that sentinel be?
>
Isn't there a problem with this starting assumption?
Say that I have item dunder code of the signature that is common today, and
I have no interest in providing direct support for kwd args in my item
dunders. Say also, kwd unpacking is supported.
If a person unpacks an empty dictionary (something that surely will happen
occasionally), and a SENTIAL is provided, this poses a pretty good
possibility to lead to unintended behavior in many cases:
class C:
def __getitem__(self, index):
...
d = {}
c = C()
c[**d]
The above will call:
c.__getitem__(SENTINEL)
Who knows what the effect of c[SENTINEL] will be for so much existing code
out there? Bugs are surely to be created, aren't they? So a lot of people
will have to make changes to existing code to handle this with a sentinel.
This seems like a big ugly problem to me that needs to be avoided.
There's a third option: just prohibit keyword-only subscripts. I think
> that's harsh, throwing the baby out with the bathwater. I personally
> have use-cases where I would use keyword-only subscripts so I would
> prefer options 1 or 2.
>
Maybe there's a middle way option that could avoid the particular problem
outlined above:
# Option 4: do use a sentinel at all, user provides own (if desired)
obj[spam=1, eggs=2]
# => calls type(obj).__getitem__(USER_PROVIDED_SENTINEL, spam=1, eggs=2)
del obj[spam=1, eggs=2]
# => calls type(obj).__delitem__(USER_PROVIDED_SENTINEL, spam=1, eggs=2)
obj[spam=1, eggs=2] = value
# => calls type(obj).__setitem__(USER_PROVIDED_SENTINEL, value, spam=1,
eggs=2)
How do we write the dunder item to allow for this? Simple: just require
that if it is desired to support kwd-only item setting, the writer of the
code has to provide a default-- ANY default-- to the value argument in
setitem (and this default will never be used).
I suggest the ellipses object as the standard convention:
MyPreferredSentinel = object()
class C:
def __setitem__(self, index=MyPreferredSentinel, value=..., **kwargs):
...
c=C()
c[x=1] = "foo"
# calls => c.__setitem__(MyPreferredSentinel, "foo", x=1)
This option provides an additional benefit: if I don't want to provide
support for the kwd-only case, I don't have to handle it explicitly--
errors occur without any effort on my part, just as they do today (although
the error itself is different):
class C:
def __setitem__(self, index, value, **kwargs):
...
c = C()
c[x=1] = "foo" # yay, this produces an error with no effort
Providing a default sentinel nullifies this possibility. In that case, have
to handle a kwd-only indexing myself:
class C:
def __setitem__(self, index, value, **kwargs):
if index is SENTINEL:
handle_kwd_args_only()
---
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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/G2ZGET57PC3QQ4AJGHZAJIWCDFXKS5QN/
Code of Conduct: http://python.org/psf/codeofconduct/