Python iterator and generator example details

  • 2020-06-01 10:15:14
  • OfStack

Python iterator and generator example details

1. How to implement iterable objects and iterator objects

1. Get the iterator object from the iterable object

For example, l is an iterable object and iter(l) is an iterator object


In [1]: l = [1,2,3,4]

In [2]: l.__iter__
Out[2]: <method-wrapper '__iter__' of list object at 0x000000000426C7C8>

In [3]: t = iter(l)

In [4]: t.next()
Out[4]: 1

In [5]: t.next()
Out[5]: 2

In [6]: t.next()
Out[6]: 3

In [7]: t.next()
Out[7]: 4

In [8]: t.next()
---------------------------------------------------------------------------
StopIteration               Traceback (most recent call last)
<ipython-input-8-3660e2a3d509> in <module>()
----> 1 t.next()

StopIteration:

for x in l : 
  print x
for  The work flow of the cycle is first iter(l) get 1 a t And call it again and again t.nex(), To the end of the capture StopIteration , the iteration ends 

The following method of directly calling a function can be adopted as an iterator if it will be more demanding on network IO when the data volume is large


def getWeather(city):
  r = requests.get(u'http://wthrcdn.etouch.cn/weather_mini?city='+city)
  data = r.json()['data']['forecast'][0]
  return '%s:%s,%s' %(city, data['low'], data['high'])
print getWeather(u' Beijing ')
 The return value: 
Beijing : The low temperature 13 ℃ , The high temperature 28 ℃

Implement 1 iterator object WeatherIterator,next method returns 1 city temperature at a time

Implement 1 iterable object WeatherIterable, and the iter method returns 1 iterator object


# -*- coding:utf-8 -*-
import requests
from collections import Iterable, Iterator

class WeatherIterator(Iterator):
  def __init__(self, cities):
    self.cities = cities
    self.index = 0

  def getWeather(self,city):
    r = requests.get(u'http://wthrcdn.etouch.cn/weather_mini?city='+city)
    data = r.json()['data']['forecast'][0]
    return '%s:%s,%s' %(city, data['low'], data['high'])

  def next(self):
    if self.index == len(self.cities):
      raise StopIteration
    city = self.cities[self.index]
    self.index += 1
    return self.getWeather(city)

class WeatherIterable(Iterable):
  def __init__(self, cities):
    self.cities = cities

  def __iter__(self):
    return WeatherIterator(self.cities)

for x in WeatherIterable([u' Beijing ',u' Shanghai ',u' Guangzhou ',u' shenzhen ']):
  print x.encode('utf-8')

 Output: 
 Beijing : The low temperature  13 ℃ , The high temperature  28 ℃ 
 Shanghai : The low temperature  14 ℃ , The high temperature  22 ℃ 
 Guangzhou : The low temperature  17 ℃ , The high temperature  23 ℃ 
 shenzhen : The low temperature  18 ℃ , The high temperature  24 ℃ 

2. Implement iterable objects using generator functions

1. Implement a class of iterable objects, which can iterate all primes in a given range

A prime number is defined as a number of natural Numbers greater than 1 that have no factors other than 1 and itself.

A function with yield is an generator, which, unlike normal functions, generates an generator that looks like a function call, but does not execute any function code until it is called next() (which is automatically called next() in the for loop). Although the execution process is still executed as the function's process, each time an yield statement is executed, an iteration value is returned, and execution continues from the next statement of yield at the next execution. It looks as if a function was interrupted several times during normal execution by yield, each interrupt returning the current iteration value via yield.


class PrimeNumbers:
  def __init__(self, start, end):
    self.start = start
    self.end = end

  def isPrimeNum(self, k):
    if k < 2:
      return False
    for i in xrange(2, k):
      if k % i == 0:
        return False

    return True

  def __iter__(self):
    for k in xrange(self.start, self.end + 1):
      if self.isPrimeNum(k):
        yield k

for x in PrimeNumbers(1, 10):
  print x

 Output: 
2
3
5
7

3. Realize reverse iteration

1. Iterate in reverse

For example, implement a floating point number generator FloatRange(similar to xrange), and generate a series of 1 consecutive floating point Numbers according to a given range (start, end) and step value (step). For example, iterative FloatRange (3.0,4.0,0.2) can produce a sequence:

Positive: 3.0 - > 3.2 - > 3.4 - > 3.6 - > 3.8 - > 4.0

Reverse: 4.0 - > 3.8 - > 3.6 - > 3.4 - > 3.2 - > 3.0


class FloatRange:
  def __init__(self, start, end, step=0.1):
    self.start = start
    self.end = end
    self.step = step

  def __iter__(self):
    t = self.start
    while round(t,14) <= round(self.end, 14):
      yield t
      t = t + self.step

  def __reversed__(self):
    t = self.end
    while round(t, 14) >= round(self.start, 14):
      yield t
      t = t - self.step

for x in reversed(FloatRange(3.0, 4.0, 0.2)):
  print x
 Output: 
4.0
3.8
3.6
3.4
3.2
3.0
for x in FloatRange(3.0, 4.0, 0.2):
    print x
Output:
3.0
3.2
3.4
3.6
3.8
4.0

The above code USES the round function because floating point comparisons have accuracy problems, so a 4 round 5 is required

2. Slice the iterator

For example, if you have a text file and want to read a certain range of contents, such as contents between 100 and 300 lines, python's Chinese version of this file is an iterable object, can you use a list-like slicer to get a generator of the contents of a 100-300 line file

Using itertools.islice in the standard library, it returns a generator that slices an iterated object


f = open('/var/log/dmesg')

from itertools import islice

#  On file content 100 to 300 Slice between the rows and return a generator object. The default diameter is 1
islice(f, 100, 300)

#  before 500 line 
islice(f, 500)

# 100 The line ends at the end 
islice(f, 100, None)


ps:  Every time I use islice To reapply an object, it consumes the original iteration object 

4. Iterate over multiple objects

1. Iterate over multiple iterable objects in one for statement

1. The Chinese, math and English test scores of a certain class are stored in three lists, and the three lists are iterated at the same time to calculate the total scores of the three students (in parallel).

2. There are 4 classes in a certain grade. The English scores of each class in a certain exam are stored in 4 lists.

Solutions:

Parallelism: USES the built-in function zip, which merges multiple iterable objects, returning one tuple per iteration


from random import randint

chinese = [randint(60,100) for _ in xrange(40)]
math = [randint(60,100) for _ in xrange(40)]
english = [randint(60,100) for _ in xrange(40)]

total = []
for c,m,e in zip(chinese, math,english):
  total.append(c+m+e)

print total

 Output: 

[204, 227, 238, 201, 227, 205, 251, 274, 210, 242, 220, 239, 237, 207, 230, 267, 263, 240, 247, 249, 255, 268, 209, 270, 259, 251, 245, 262, 234, 221, 236, 250, 251, 249, 242, 255, 232, 272, 237, 253]

Serial: USES itertools.chain from the standard library to connect multiple iterable objects


from random import randint
from itertools import chain

class1 = [randint(60,100) for _ in xrange(40)]
class2 = [randint(60,100) for _ in xrange(42)]
class3 = [randint(60,100) for _ in xrange(39)]
class4 = [randint(60,100) for _ in xrange(43)]

count = 0
for s in chain(class1, class2, class3, class4):
  if s > 90:
    count = count + 1

print count

 Output: 
38


Thank you for reading, I hope to help you, thank you for your support of this site!


Related articles: