[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