Terry J. Reedy added the comment: The problem with the Iterable ABC is that 'iterable' and 'iterator' are *dynamically* defined, with a possibly infinite time required to possibly destructively check either definition. In general, an algorithmic *static* check can only guess whether an object is iterable, though humans analyzing enough code can potentially get it right. Therefore, using isinstance(ob, Iterable) is not 100% reliable, and in my opinion *should not be used* as the definition of lower-case 'iterable'.
Definition: Object ob is iterable if 'iter(ob)' returns an iterator. For the reasons given above, iter may return a non-iterator, but it will if ob implements either the old or new iterator protocol. If ob has .__iter__, iter returns ob.__iter__(). If ob has .__getitem__, iter returns iterator(ob), where iterator is a hidden internal class that embodies the old iterator protocol by defining a .__next__ method that calls .__getitem__. In both cases, iter does the best it can by assuming that the methods are correctly written as per one of the two protocols. Loose definition: Object 'it' is iterable if it can be looped over. Python definition: Object 'it' is iterable if repeated 'next(it)' calls either return an object or raise StopIteration. This means that try: while True: next(it) except StopIteration: pass runs, possibly forever, without raising. As Raymond noted, an iterator can be created multiple ways: IteratorClass(), iter(ob), iter(func, sentinal), generator_func(). --- Iterable versus iter with respect to classes with __getitem__: Iter was added in 2.2. Built-in iterables were only gradually converted from old to new protocol, by adding a new .__iter__. So even ignoring user classes, iter *had* to respect .__getitem__. Even today, though only a small fraction of classes with .__getitem__ are iterable, people do not generally call iter() on random objects. Iterable (added 2.6) is documented as the "ABC for classes that provide the __iter__() method." In other words, isinstance(ob, Iterable) replaces hasattr(ob, '__iter__'). Except that the former is more than that. The magic word 'register' does not appear in the collections.ABC doc, and I think that this is the omission to be remedied. "ABC for classes that provide the __iter__() method, or that provide a __getitem__ method that implements the old iterator protocol and register themselves as Iterable." An example could be given using a patched version of IsIterable. If one adds two lines of code from collections.abc import Iterable ... Iterable.register(IsIterable) then isinstance(IsIterable(3), Iterable) is True, except that this is a lie in the other direction. Traceback (most recent call last): File "F:\Python\mypy\tem.py", line 17, in <module> for i in it2: File "F:\Python\mypy\tem.py", line 7, in __getitem__ return self.data[key] TypeError: 'int' object is not subscriptable Either IsIterable.__init__ must check that data itself has .__getitem__ or IsIterable.__next__ must capture exceptions and raise IndexError instead. def __getitem__(self, key): try: return self.data[key] except Exception: raise IndexError ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue18558> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com