[Tutor] _next
Kent Johnson
kent37 at tds.net
Thu May 25 04:31:32 CEST 2006
Christopher Spears wrote:
> How does this script work?
>
> #!/usr/bin/python
>
> class IteratorExample:
> def __init__(self, s):
> self.s = s
> self.next = self._next().next
> self.exhausted = 0
> def _next(self):
> if not self.exhausted:
> flag = 0
> for x in self.s:
> if flag:
> flag = 0
> yield x
> else:
> flag = 1
> self.exhausted = 1
> def __iter__(self):
> return self._next()
>
> def main():
> a = IteratorExample('edcba')
> for x in a:
> print x
> print '=' * 30
> a = IteratorExample('abcde')
> print a.next()
> print a.next()
> print a.next()
> print a.next()
> print a.next()
> print a.next()
>
> if __name__ == '__main__':
> main()
>
>
> Here is the output:
>
> d
> b
> ==============================
> b
> d
> Traceback (most recent call last):
> File "./python_101_iterator_class.py", line 35, in ?
> main()
> File "./python_101_iterator_class.py", line 29, in
> main
> print a.next()
> StopIteration
>
> I think a lot of my confusion comes from not
> understanding what _next is. I got this script from
> an online tutorial at python.org. Is there a better
> way to write the script, so I can actually understand it?
_next() is a generator - a function which, when called, returns an
iterator. Each time the yield statement is reached, the iterator returns
a new value. When the generator returns, the iteration ends. Generators
are a very convenient way to package up iteration and state. Here is a
simple example of a generator that counts to 2:
In [1]: def count2():
...: yield 1
...: yield 2
...:
...:
You can iterate over the generator in a for loop:
In [2]: for i in count2():
...: print i
...:
...:
1
2
If you prefer you can explicitly call the next() method, which is a
common method of all iterators:
In [3]: c=count2()
In [4]: c.next()
Out[4]: 1
In [5]: c.next()
Out[5]: 2
When the iterator is exhausted, it raises StopIteration. Again, this is
standard behaviour for all iterators:
In [6]: c.next()
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in ?
StopIteration
Your example seems like a complicated way to wrap an iterable in an
iterator which returns every other element. Maybe I am missing
something, but I would write it like this:
In [7]: def skipper(seq):
...: it = iter(seq) # make sure we have an iterator
...: while True:
...: it.next() # skip a value
...: yield it.next() # return a value
...:
...:
In [8]: for a in skipper('edcba'):
...: print a
...:
...:
d
b
In [9]: a = skipper('edcba')
In [10]: a.next()
Out[10]: 'd'
In [11]: a.next()
Out[11]: 'b'
In [12]: a.next()
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in ?
File "<ipython console>", line 5, in skipper
StopIteration
You can read more about the iterator protocol and generators here:
http://www.python.org/doc/2.2.3/whatsnew/node4.html
http://www.python.org/doc/2.2.3/whatsnew/node5.html
Read the referenced PEPs for all the juicy details.
Hmm, a little Googling finds the tutorial you mention here:
http://www.rexx.com/~dkuhlman/python_101/python_101.html#SECTION004460000000000000000
IMO this is a very confused example. You can write class-based iterators
and you can write generator-based iterators, but combining them both to
achieve such a simple result makes no sense to me.
Kent
More information about the Tutor
mailing list