Le dimanche 9 août 2015 11:25:17 UTC+2, Chris Angelico a écrit : > On Sun, Aug 9, 2015 at 7:06 PM, Pierre Quentel <pierre.quen...@gmail.com> > wrote: > > "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." > > > > ... > > I get an assertion error. Setting a trace on __next__ suggests that for > > membership testing, the interpreter consumes the iterator until the searched > > value is found (or until exhaustion), then it resumes iteration at this > > point. > > That's exactly right. The only way for the interpreter to handle 'in' > on an iterator is something like this: > > def contains(iter, obj): > for val in iter: > if val == obj: return True > return False > > That's what the docs describe. So what you have is something like this: > > for i in iterator: > for j in iterator: > if i == j: break > else: > assert False, '%s not found' %i > > You're dragging values from the same iterator, so you're consuming it > as part of your membership test. You can do this kind of thing: > > >>> 5 in A(10) > True > > but if you've already consumed a few values, those won't be in the > iterator any more: > > >>> x = A(10) > >>> next(x) > 0 > >>> next(x) > 1 > >>> next(x) > 2 > >>> next(x) > 3 > >>> 2 in x > False > > This is simply how iterators work. They're very different from > repeatable iterables like lists or range objects, where you _can_ test > for membership that way: > > >>> x = [10,20,30] > >>> for i in x: assert i in x > ... > >>> x = iter([10,20,30]) > >>> for i in x: assert i in x > ... > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > AssertionError > > Note that I _could_ create a list that would pass this assertion, > simply by duplicating every value: > > >>> x = iter([10,10,20,20,30,30]) > >>> for i in x: assert i in x > ... > > But it's iterating only three times here, and the 'in' check is > consuming the other three values. Once your A(10) has yielded some > value, it will never yield it again, so the assertion can never pass. > > Does that explain matters? > > ChrisA
Thanks for the explanation. I understand that an iterator can't test membership any other way, but I'm still worried about how the documentation explains it. Reading it, I naively expected that an iterator which produces the integer 0 such as the one included in my post would say that "0 in iterator" is True, because "some value z with 0 == z is produced while iterating over y". Shouldn't it be more clear if the documentation said something like : "For user-defined classes which do not define __contains__() but do define __iter__(), x in y consumes the iterator y until some value z with x == z is produced" ? -- https://mail.python.org/mailman/listinfo/python-list