On Wed, Aug 26, 2020 at 7:56 PM Guido van Rossum <gu...@python.org> wrote:

> On Wed, Aug 26, 2020 at 10:45 AM Alex Hall <alex.moj...@gmail.com> wrote:
>
>> On Wed, Aug 26, 2020 at 7:30 PM Guido van Rossum <gu...@python.org>
>> wrote:
>>
>>> But for your convenience you are proposing a problematic change (see
>>> posts by others).
>>>
>>
>> I think we've established it's problematic to add it to the Sequence ABC,
>> but in terms of only adding it to specific sequences like lists, I don't
>> know what other posts you're referring to. Why is it problematic?
>>
>
> It would break duck typing -- if you check for IndexError you can accept
> pretty much any sequence. But if you use .get() you can only work with
> lists.
>
> This is why we have ABCs in the first place (and static checking). So that
> you can't add it to Sequence is already a smell. If it's in the Mapping
> protocol, why isn't it in the Sequence protocol?
>

This is all just a general feature of ABCs. They were written once and
frozen in place and no new methods can be added to them because it would
break compatibility. It's not specific to this proposal. | and |= operators
were added to dict but not to Mapping/MutableMapping for the same reason,
even though the same operators exist with a similar meaning in the
Set/MutableSet protocols. So there's a clear precedent for this.

It's a little unfortunate that we can't put this in the Sequence ABC, but
it's not a big deal. The vast majority of the time I'm interfacing with my
own code and so I know that I'm working with a list, not some mysterious
Sequence. I don't think people are going to change their public facing
function signatures from `def foo(x: Sequence)` to `(x: list)` just so that
they can use `x.get`. Even if they do, it suggests that they think `.get`
is really useful, and callers can just convert their argument to a list
first. Similarly adding the union operator to dict is fine because people
usually use dicts, not generic Mappings.

Besides, list already defines a bunch of stuff not found in Sequence or
MutableSequence: copy, sort, `<`, `+`, and `*`. What's one more?


> There's also the slippery-slope argument brought up earlier -- should it
> be added to tuple? To range?
>

I think Steven D'Aprano asked this. I don't see it as an argument against
or a concern about a slippery slope, just a question. I think it'd be nice
to have it on lots of sequences, but it's OK if it's not. Neither scenario
strikes me as problematic.

The union operator was also added to defaultdict, OrderedDict, and
ChainMap. Was this a problem?


> What should it do for a negative index?
>

I think most people expect that if `lst[i]` returns a value then
`lst.get(i)` should return the same value, therefore it should return a
default only when `lst[i]` fails. Sometimes you specifically want
`lst.get(-1)` - there's a couple examples of that in [my earlier post](
https://mail.python.org/archives/list/python-ideas@python.org/message/7W74OCYU5WTYFNTKW7PHONUCD3U2S3OO/)
and Daniel recently presented a case when he wanted that.

This isn't the ideal behaviour for all use cases, but only as much as
normal indexing isn't the ideal behaviour for all use cases. Sometimes I've
had bugs because I forgot to account for negative indices, but I'm still
very grateful to you that negative indices work. We can't make something
equally convenient for all use cases, but that doesn't diminish the value
of this method.

You said yourself that the generic alternative for all sequences is to
"check for IndexError", a sign that doing the equivalent of that is more
intuitive.


> I also think it negatively affects readability. Today when I see
> `foo.get(bar)` I assume that (unless the code is full of tricks) foo is a
> dict or Mapping
>

That's already a poor assumption to make. `get` is an extremely generic
method name that has lots of meanings in different classes.


> But if list also grows a .get() method I have to assume in my head that
> foo is a list and then bar an int, and I basically have to read the rest of
> the code twice, once assuming foo is a Mapping, and once assuming it's a
> list.
>

The purpose of `foo.get(bar)` is to get a value, not to tell you that foo
is a dict. If the rest of the code isn't able to tell you whether `foo` is
a dict or a list, then either the code is poorly written (and .get is not
to blame) or it doesn't matter because you're just getting individual
values. `foo[bar]` doesn't differentiate between lists and dicts and this
is generally considered a good thing, not a problem.


> The generalization I am talking about here is the assumption that because
> list and dict both support x[y], and dict also has x.get(y) which returns a
> default instead of raising, then it would be a good idea to add the latter
> also to list.
>

I'm not assuming that list should have .get because dict has it. I'm
claiming list should have it because it would often be useful, based on
[empirical evidence](
https://mail.python.org/archives/list/python-ideas@python.org/message/7W74OCYU5WTYFNTKW7PHONUCD3U2S3OO/
).

Anyway, thank you for this. I'm enjoying the discussion and I'm glad to
hear actual reasons that can be argued about rather than the proposal just
fizzling away.
_______________________________________________
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/K2PMSIJQ27TS2JJUKPV3ASLJJ4HTVTBP/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to