[Tutor] reading an input stream

eryk sun eryksun at gmail.com
Thu Dec 24 23:05:55 EST 2015


On Thu, Dec 24, 2015 at 9:13 PM, boB Stepp <robertvstepp at gmail.com> wrote:
> AttributeError: 'generator' object has no attribute 'next'

The iterator protocol was added in Python 2.2 (circa 2001) as a
generalization for use in "for" loops, but the language didn't have
built-in next() at the time. Instead the method to get the next item
from an iterator was defined without double underscores. You'd simply
call it.next() to manually get the next item of iterator "it".

Python 3 added built-in next() and changed the method name to
"__next__". The built-in function was backported to 2.6 to have a
common idiom even though the method is still named "next" in Python 2.

The name change in Python 3  reflects that "__next__" is a special
method that's looked up on the type (in CPython it's the tp_iternext
field of the PyTypeObject). You can't simply add a bound next method
to an instance to make Python think it's an iterator. The same applies
in Python 2, but the name "next" doesn't suggest that this is the
case.

For example, let's start out with a normal Python 2 iterator that
simply iterates a count from some initial value.

    class Iterator(object):
        def __init__(self, start):
            self.value = start - 1
        def __iter__(self):
            return self
        def next(self):
            self.value += 1
            return self.value

    >>> it = Iterator(0)
    >>> it.next()
    0
    >>> next(it)
    1

Now store the bound next method directly on the instance

    >>> it.next = it.next
    >>> it.next.__self__ is it
    True

and remove the method from the class:

    >>> del Iterator.next

The bound method still works:

    >>> it.next()
    2

But the interpreter doesn't look for "next" on the instance:

    >>> next(it)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: Iterator object is not an iterator

    >>> for i in it:
    ...     if i == 3: break
    ...
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: iter() returned non-iterator of type 'Iterator'

Since "next" is a special method, it should have the special name
"__next__". So let it be written. So let it be done... in Python 3.


More information about the Tutor mailing list