[Python-ideas] __iter__ implies __contains__?

Masklinn masklinn at masklinn.net
Sat Oct 1 20:27:03 CEST 2011


On 2011-10-01, at 20:13 , Antoine Pitrou wrote:
> Hello,
> 
> I honestly didn't know we exposed such semantics, and I'm wondering if
> the functionality is worth the astonishement:
> 
>>>> "abc" in io.StringIO("abc\ndef\n")
> False
>>>> "abc\n" in io.StringIO("abc\ndef\n")
> True
> 
> Basically, io.StringIO provides iteration (it yields lines of text) and
> containment is apparently inferred from that.
There's a second fallback: Python will also try to iterate using
__getitem__ and integer indexes __iter__ is not defined.

The resolution is defined in the expressions doc[0]:

> For user-defined classes which define the __contains__() method, x in
> y is true if and only if y.__contains__(x) is true.
>
> For user-defined classes which do not define __contains__() but do
> define __iter__(), x in y is true if some value z with x == z is
> produced while iterating over y. If an exception is raised during the
> iteration, it is as if in raised that exception.
>
> Lastly, the old-style iteration protocol is tried: if a class defines
> __getitem__(), x in y is true if and only if there is a non-negative
> integer index i such that x == y[i], and all lower integer indices do
> not raise IndexError exception. (If any other exception is raised, it
> is as if in raised that exception).

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.

I don't know if there's any way to make a class with an __iter__ or a
__getitem__ respectively non-containing and non-iterable (apart from
adding the method and raising an exception)

[0] http://docs.python.org/reference/expressions.html#notin



More information about the Python-ideas mailing list