Differences between revisions 1 and 7 (spanning 6 versions)
Revision 1 as of 2005-04-02 23:58:27
Size: 1350
Editor: aaron
Comment: basics
Revision 7 as of 2021-01-19 09:53:44
Size: 2808
Editor: eriky
Comment: fixed function name, added extra explanations, added section on iter() and next(), added links to itertools docs, functional programming docs, and a link explaining iterator basics more thoroughly
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
An '''iterator''' is an object that implements {{{__iter__}}} and and {{{next}}}. An '''iterable''' object is an object that implements {{{__iter__}}}, which is expected to return an '''iterator''' object.
Line 3: Line 3:
You can use them in for loops, and you can use them to construct lists. An '''iterator''' is an object that implements {{{__next__}}}, which is expected to return the next element of the iterable object that returned it, and raise a {{{StopIteration}}} exception when no more elements are available.

In the simplest case the iterable will implement {{{__next__}}} itself and return {{{self}}} in {{{__iter__}}}. However, this has its limitations and will produce unexpected results when used in concurrent environments (e.g. with the multiprocessing API).

You can use iterables in for loops and you can use them to construct lists, using list comprehensions or by using the {{{list}}} function.
Line 13: Line 17:
class RandomIterator: class RandomIterable:
Line 16: Line 20:
    def next(self):     def __next__(self):
Line 24: Line 28:
'''A:''' This is so that the iterator can be used in a for...in loop. '''A:''' This is a very simple case. More complex iterables may very well return separate iterator objects.

'''Q:''' When would I need an extra iterator?

'''A:''' Iterator will typically need to maintain some kind of position state information (like the index of the last element returned or the like). If the iterable maintained that state itself, it would become inherently non-reentrant (meaning you could use it only one loop at a time).
Line 28: Line 36:
for eggs in RandomIterator():
    print eggs
for eggs in RandomIterable():
    print(eggs)
Line 36: Line 44:
>>> list(RandomIterator()) >>> list(RandomIterable())
Line 38: Line 46:
>>> list(RandomIterator()) >>> list(RandomIterable())
Line 40: Line 48:
>>> list(RandomIterator()) >>> list(RandomIterable())
Line 42: Line 50:
>>> list(RandomIterator()) >>> list(RandomIterable())
Line 48: Line 56:
An object isn't an iterator unless it provides ''both'' methods. If it ''does'' provide these methods, then it's an iterator. An object isn't iterable unless it provides {{{__iter__}}}. And for an object to be a valid iterator, it must provide {{{__next__}}}.

== Manual usage ==
Although you won't need this in most cases, you can manually get the iterator from an iterable object by using the {{{iter()}}} function. Similary, you can manually call {{{__next___}}} using the {{{next()}}} function.
Line 52: Line 63:
 * [http://www.python.org/peps/pep-0234.html PEP-234: Iterators]
 * [http://www-106.ibm.com/developerworks/library/l-pycon.html?n-l-9271 Iterators & Simple Generators]
 * [[http://www.python.org/peps/pep-0234.html|PEP-234: Iterators]]
 * [[https://docs.python.org/3/library/itertools.html|Itertools: Functions creating iterators for efficient looping]]
 * [[https://docs.python.org/3/howto/functional.html?highlight=iterator#functional-howto-iterators|Functional programming and iterators]]
 * [[https://python.land/deep-dives/python-iterator|Python iterator basics (how they work + examples)]]
Line 55: Line 68:
See also: ["Generators"]

= Discussion =

  (none yet!)
See also: [[Generators]]

An iterable object is an object that implements __iter__, which is expected to return an iterator object.

An iterator is an object that implements __next__, which is expected to return the next element of the iterable object that returned it, and raise a StopIteration exception when no more elements are available.

In the simplest case the iterable will implement __next__ itself and return self in __iter__. However, this has its limitations and will produce unexpected results when used in concurrent environments (e.g. with the multiprocessing API).

You can use iterables in for loops and you can use them to construct lists, using list comprehensions or by using the list function.

Example Iterator

Here is an iterator that returns a random number of 1's:

   1 import random
   2 
   3 class RandomIterable:
   4     def __iter__(self):
   5         return self
   6     def __next__(self):
   7         if random.choice(["go", "go", "stop"]) == "stop":
   8             raise StopIteration  # signals "the end"
   9         return 1

Q: Why is __iter__ there, if it just returns self?

A: This is a very simple case. More complex iterables may very well return separate iterator objects.

Q: When would I need an extra iterator?

A: Iterator will typically need to maintain some kind of position state information (like the index of the last element returned or the like). If the iterable maintained that state itself, it would become inherently non-reentrant (meaning you could use it only one loop at a time).

   1 for eggs in RandomIterable():
   2     print(eggs)

You can also use it in list construction:

   1 >>> list(RandomIterable())
   2 [1]
   3 >>> list(RandomIterable())
   4 []
   5 >>> list(RandomIterable())
   6 [1, 1, 1, 1, 1]
   7 >>> list(RandomIterable())
   8 [1]

...both of these uses require __iter__.

An object isn't iterable unless it provides __iter__. And for an object to be a valid iterator, it must provide __next__.

Manual usage

Although you won't need this in most cases, you can manually get the iterator from an iterable object by using the iter() function. Similary, you can manually call __next___ using the next() function.

See also: Generators

Iterator (last edited 2021-12-11 12:50:13 by ChrisM)

Unable to edit the page? See the FrontPage for instructions.