[Python-ideas] Changing `Sequence.__contains__`
Andrew Barnert
abarnert at yahoo.com
Mon Jul 21 03:52:58 CEST 2014
On Sunday, July 20, 2014 6:42 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> > On Sun, Jul 20, 2014 at 03:06:33PM -0700, Ram Rachum wrote:
>
>> Why does the default `Sequence.__contains__` iterate through the items
>> rather than use `.index`, which may sometimes be more efficient?
>
> Because having an index() method is not a requirement to be a sequence.
> It is optional.
Sequence.__contains__ certainly can assume that your class will have an index method, because it provides one if you don't. See https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes (and you can look all the way back to 2.6 and 3.0 to verify that it's always been there).
The default implementation looks like this:
for i, v in enumerate(self):
if v == value:
return i
raise ValueError
> but it has at two problems I can see:
>
> - it's not backwards compatible with sequence types which may already
> define an index attribute which does something different, e.g.:
>
> class Book:
> def index(self):
> # return the index of the book
This isn't a Sequence. You didn't inherit from collections.abc.Sequence, or even register with it. So, Sequence.__contains__ can't get called on your class in the first place.
If you _do_ make it a Sequence, then you're violating the protocol you're claiming to support, and it's your own fault if that doesn't work. You can also write a __getitem__ that requires four arguments and call yourself a Sequence, but you're going to get exceptions all over the place trying to use it.
> For a historical view, you should be aware that until recently, tuples
> had no index method:
That was true up until the collections ABCs were aded in 2.6 and 3.0. Prior to that, yes, the "sequence protocol" was a vague thing, and you couldn't be sure that something had an index method just because it looked like a sequence—but, by the same token, prior to that, there was no Sequence ABC mixin, so the problem wasn't relevant in the first place.
More information about the Python-ideas
mailing list