On Tue, Dec 29, 2020 at 10:30:16AM -0800, Guido van Rossum wrote:

[Christopher]
> > Does there need to be a single defined "protocol" for a mapping (other
> > than the ABC)? -- that is, would **unpacking be able to use .items() and
> > keys() be used in other contexts?

Yes, I think there should be one protocol, or interface if you prefer, 
for something to be considered dict-like. If some operations expect 
objects to quack like a dict, then it would be annoying if other related 
operations expect them to swim like a dict.

The status quo right now is:

(1) The dict constructor, dict.update, and dict union assignment `|=` 
all support the double-barrelled interface:

- try keys() and `__getitem__`

- otherwise fall back onto direct iteration.

(2) Dict unpacking `**` only supports the keys/getitem interface.

My guess is that's an oversight, not a deliberate difference in 
behaviour.

I think that those four operations should operate in a consistant 
manner.

Otherwise, we would be okay if we can write a object that quacks like a 
dict via keys/getitem, since that is supported by all four, but suppose 
you can't and have to use the fallback operation.

So you dutifully add the direct iteration API, and now your object works 
in the dict constructor etc but not dict unpacking. So you have to 
*also* add the items() method you suggest, an otherwise unnecessary 
second way of doing the same thing. This is annoying and error-prone: 
being two methods, there is a risk that they will diverge in behaviour, 
or that documentation will diverge, and now users of your object need to 
worry about whether to use direct iteration or items(), and you know 
that people will keep asking what's the difference between them.

It wouldn't be a disaster if we went this way, but it would add 
unnecessary friction.

There is however a third possibility: extend the dict interface by 
adding a second fallback. I think we're stuck with keeping the existing 
order as first and second attempts, but we can tack items() at the end:

- try keys() and `__getitem__`

- try direct iteration

- otherwise, try items()

I don't hate this, but honestly I think it is YAGNI.



[Guido] 
> I don't understand why LBYL is considered such an anti-pattern. It helps
> produce much clearer error messages in this case for users who are
> exploring this feature, and distinguishing *early* between sequences and
> mappings is important for that. Long ago we decided that the distinctive
> feature is that mappings have a `keys()` method whereas sequences don't
> (and users who add a `keys()` method to a sequence are just asking for
> trouble). So that's what we use.

I remember learning that EAPF was preferred over LBYL back when I 
started in Python 1.5 days. I think the main reasons were to encourage 
people to duck-type, and to avoid Time Of Check To Time Of Use errors, 
e.g. when opening files. But although EAFP was preferred, there are 
definitely times when LBYL is better, and I think that calling LBYL 
"unPythonic" is a hyper-correction.


-- 
Steve
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/OTC5HL2XC2SRGEQLOKMIOUM5L5IDGTFW/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to