Python's iterators and generators use instances

  • 2020-04-02 14:29:22
  • OfStack

One, Iterators

An iterator is simply a container object that implements the iterator protocol. It has two basic methods:

1) next method
Returns the next element of the container

2) s method
Returns the iterator itself

Iterators can be created using the built-in iter method, see examples:


>>> i = iter('abc')
>>> i.next()
'a'
>>> i.next()
'b'
>>> i.next()
'c'
>>> i.next()
Traceback (most recent call last):
  File "<string>", line 1, in <string>
StopIteration: class MyIterator(object):
  def __init__(self, step):
  self.step = step
  def next(self):
  """Returns the next element."""
  if self.step==0:
  raise StopIteration
  self.step-=1
  return self.step
  def __iter__(self):
  """Returns the iterator itself."""
  return self
for el in MyIterator(4):
  print el
--------------------

Results:

3
2
1
0

Two, generator power

Starting with Python2.2, generators provide a concise way to help return functions of list elements to complete simple and efficient code.
It is based on the yield directive, allowing the function to be stopped and the result to be returned immediately.

This function saves its execution context and can continue execution immediately if needed.

For example, the Fibonacci function:


def fibonacci():
  a,b=0,1
  while True:
  yield b
  a,b = b, a+b
fib=fibonacci()
print fib.next()
print fib.next()
print fib.next()
print [fib.next() for i in range(10)]
--------------------

Results:

1
1
2
[3, 5, 8, 13, 21, 34, 55, 89, 144, 233]

PEP Python Enhancement Proposal Python Enhancement Proposal

Tokenize module


>>> import tokenize
>>> reader = open('c:/temp/py1.py').next
>>> tokens=tokenize.generate_tokens(reader)
>>> tokens.next()
(1, 'class', (1, 0), (1, 5), 'class MyIterator(object):/n')
>>> tokens.next()
(1, 'MyIterator', (1, 6), (1, 16), 'class MyIterator(object):/n')
>>> tokens.next()
(51, '(', (1, 16), (1, 17), 'class MyIterator(object):/n')

Example:

def power(values):
  for value in values:
  print 'powering %s' %value
  yield value
def adder(values):
  for value in values:
  print 'adding to %s' %value
  if value%2==0:
  yield value+3
  else:
  yield value+2
elements = [1,4,7,9,12,19]
res = adder(power(elements))
print res.next()
print res.next()
--------------------

Results:

powering 1
adding to 1
3
powering 4
adding to 4
7

Keep the code simple, not the data.
Note: it is better to have a large number of simple iterable functions than a complex function that only computes one value at a time.

Example:


def psychologist():
  print 'Please tell me your problems'
  while True:
  answer = (yield)
  if answer is not None:
  if answer.endswith('?'):
  print ("Don't ask yourself too much questions")
  elif 'good' in answer:
  print "A that's good, go on"
  elif 'bad' in answer:
  print "Don't be so negative"
free = psychologist()
print free.next()
print free.send('I feel bad')
print free.send("Why I shouldn't ?")
print free.send("ok then i should find what is good for me")
--------------------

Results:

Please tell me your problems
None
Don't be so negative
None
Don't ask yourself too much questions
None
A that's good, go on
None


Related articles: