Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How come an object that implements __iter__ is not recognized as iterable?

Let's say you work with a wrapper object:

class IterOrNotIter:
    def __init__(self):
        self.f = open('/tmp/toto.txt')
    def __getattr__(self, item):
        try:
            return self.__getattribute__(item)
        except AttributeError:
            return self.f.__getattribute__(item)

This object implements __iter__, because it passes any call to it to its member f, which implements it. Case in point:

>>> x = IterOrNotIter()
>>> x.__iter__().__next__()
'Whatever was in /tmp/toto.txt\n'

According to the documentation (https://docs.python.org/3/library/stdtypes.html#iterator-types), IterOrNotIter should thus be iterable.

However, the Python interpreter does not recognize an IterOrNotIter object as actually being iterable:

>>> x = IterOrNotIter()
>>> for l in x:
...    print(l)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'IterOrNotIter' object is not iterable

Whereas this works:

>>> x = IterOrNotIter()
>>> for l in x.f:
...    print(l)
...
Whatever was in /tmp/toto.txt

I don't understand why.

like image 282
user589082 Avatar asked Oct 18 '22 12:10

user589082


1 Answers

Basically because your class just doesn't have a real __iter__ method:

>>> hasattr(IterOrNotIter, '__iter__')
False

So it doesn't qualify as iterator because the actual check for __iter__ checks for the existence instead of assuming it's implemented. So workarounds with __getattr__ or __getattribute__ (unfortunatly) don't work.

This is actually mentioned in the documentation for __getattribute__:

Note

This method may still be bypassed when looking up special methods as the result of implicit invocation via language syntax or built-in functions. See Special method lookup.

The latter section also explains the why:

Bypassing the __getattribute__() machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).

Emphasis mine.

like image 119
MSeifert Avatar answered Oct 21 '22 06:10

MSeifert