[Python-ideas] __iter__ implies __contains__?

Steven D'Aprano steve at pearwood.info
Sun Oct 2 03:14:01 CEST 2011


Chris Rebert wrote:

> <snip>
>> the latter kicks in any time an object with no __iter__ and a __getitem__
>> is tentatively iterated, I've made that error a few times with
>> insufficiently defined dict-like objects finding themselves (rightly
>> or wrongly) being iterated.
> 
> Requiring the explicit marking of a class as a sequence by inheriting
> from the Sequence ABC in order to get such default behavior "for free"
> seems quite reasonable. And having containment defined by default on
> potentially-infinite iterators seems unwise. +1 on the suggested
> removals.

These changes don't sound even close to reasonable to me. It seems to me 
that the OP is making a distinction that doesn't exist.

If you can write this:

x = collection[0]; do_something_with(x)
x = collection[1]; do_something_with(x)
x = collection[2]; do_something_with(x)
# ... etc.

then you can write it in a loop by hand:

i = -1
try:
     while True:
         i += 1
         x = collection[i]
         do_something_with(x)
except IndexError:
     pass


But that's just a for-loop in disguise. The for-loop protocol goes all 
the way back to Python 1.5 and surely even older. You should, and can, 
be able to write this:

for x in collection:
     do_something_with(x)


Requiring collection to explicitly inherit from a Sequence ABC breaks 
duck typing and is anti-Pythonic.

I can't comprehend a use-case where manually extracting collection[i] 
for sequential values of i should succeed, but doing it in a for-loop 
should fail. But if you have such a use-case, feel free to define 
__iter__ to raise an exception.

Since iteration over elements is at the heart of containment tests, the 
same reasoning applies to __contains__.


-- 
Steven



More information about the Python-ideas mailing list