Python Forum
Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Generators/Iterators
#1
Iterators are simple objects which can be iterated over, and which can be interrupted, and continued later on. If you have an iterable such as a list, string, set, tuple, etc., you can produce an iterator from them with the built-in iter() keyword.
>>> string = "hello there i am a string"
>>> iter_string = iter(string)
>>> for char in iter_string:
   if char != ' ':
       print char,
   else:
       break

   
h e l l o
>>> for char in iter_string:
   if char != ' ':
       print char.upper(),
   else:
       break

   
T H E R E
>>> print ''.join(iter_string)
i am a string
File objects are a special case iterator which iterates over the lines of the file. File objects are more powerful than the iterators returned by iter() however because you can rewind them. An iterator or generator may be rewound or reset, however those return by iter() are not. If you want to use a while loop on an iterator, you get the next item with the built-in next() method and you must catch a StopIteration once the iterator is exhausted.

Generators are a way of generating values (usually for a loop) without creating those values in advance. It can be said that iterators are a special case of generators. Where an iterator iterates over something which exists in memory already, generators produce their values "on the fly". Generators look much like functions except instead of return they use yield, for example
>>> from itertools import count # xrange with no upper limit
>>> def squares_gen(start=2):
   for x in count(start):
       yield x**2

       
>>> squares = squares_gen()
>>> for square in squares:
   if square > 100:
       break
   print square

   
4
9
16
25
36
49
64
81
100
When yield is used, execution of the generator is suspended, and is resumed when next() is called on it (which happen implicitly in a for loop). I wrote this such that it is an infinite generator, however you could specify an upper bound as a parameter as well.

Generator tricks
>>> def take_pairs(iterable):
   it = iter(iterable)
   return zip(it, it)

>>> take_pairs([1, 2, 3, 4, 5, 6])
[(1, 2), (3, 4), (5, 6)]
Questions and comments welcome as always, and I'll leave it up to the community to come up with more generator tricks.


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020