Is "... object is not iterable" A Misleading Error For "x in y"?

Viewed 1931

Consider the following two classes:

class Foo0(object):                                                 
    pass

class Foo1(object):
    def __contains__(self, _):
        return False

Neither of them is iterable, as can be observed by trying for i in Foo1(): pass:

Traceback (most recent call last):
   File "stuff.py", line 11, in <module>
    for i in Foo1(): pass
TypeError: 'Foo1' object is not iterable

Conversely, 3 in Foo1() is valid (as Foo1 has __contains__), whereas 3 in Foo0() is not:

Traceback (most recent call last):
  File "stuff.py", line 9, in <module>
    3 in Foo0()
TypeError: argument of type 'Foo0' is not iterable

I find the error misleading. The point is not that Foo0 is not iterable - after all Foo1 is not iterable too, so that's not the inherent reason. Moreover, as @niemmi and @tobias_k correctly note below, if a class does not support __contains__, __iter__ is used as a fallback, which is the direct cause for this error. However this makes things worse, as a user might try to solve this error by implementing __iter__, which is a very inefficient means of implementing __contains__.

Why was this chosen as the error, then?

1 Answers
Related