2 迭代器与生成器

iterable 可迭代对象

直接作用于for循环的对象统称为可迭代对象
如(一类是集合数据类型如list, tuple, dict, set, str等; 另一类是generator,包括生成器和带yield的generator function)

iterator 迭代器

顾名思义,迭代器就是用于迭代操作(for循环)的对象,它像列表一样可以迭代获取其中每一个元素,
任何实现了__next__方法(python2是next())的对象都可以称为迭代器。
即可以被next()函数调用并不断返回下一个值直到没有数据抛出StopIteration错误  

python的Iterator对象表示的是一个数据流,可以把这个数据流看做成一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据是才会计算

# 实现迭代器 
# 实现了__iter__方法的对象是可迭代的,实现了__next__()(python2中next())方法的对象是迭代器
# __iter__() 返回可迭代对象; __next__() 则返回每次调用 next() 或迭代时的元素;
# --------------------------------------------
class Container:
    def __init__(self, start = 0, end = 0):
        self.start = start
        self.end = end
    def __iter__(self):
        print("I made this Iterator!")
        return self
    def __next__(self):
        print("Calling __next__ method!")
        if self.start < self.end:
            i = self.start
            self.start += 1
            return i
        else:
            raise StopIteration()
c = Container(0, 5)
for i in c:
    print(i)
# -----------输出-------------    
I made this Iterator!
Calling __next__ method!
0
Calling __next__ method!
1
Calling __next__ method!
2
Calling __next__ method!
3
Calling __next__ method!
4
Calling __next__ method!

# ---------------------第二种方法-----------------
# 通过iter()函数将list, dict, str等iterable 变成 iterator 

from collections import Iterator

isinstance(iter([1,2,3]), Iterator) ---> True

generator 生成器

一遍循环以便计算的机制,称为生成器
生成器都是iterator对象
生成器通过 yield 语句快速生成迭代器,省略了复杂的 __iter__() & __next__() 方式:
# 实现生成器
# 第一种方法 把一个列表生成式的[]改成()
g = (x for x in range(1, 3))
>>> <generator object <genexpr> at 0x0000020029E7FE60>
next(g)
>>> 1
next(g)
>>> 1
next(g)
>>> StopIteration: 

# ---------使用在函数中yield语句
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n += 1
    return 'done'
a = fib(10)  # 返回的是一个生成器对象 通过next(a)调用
a
<generator object fib at 0x0000020029E7FE08>

python进阶笔记
这里写图片描述

import requests
from collections import Iterator, Iterable
class WeatherIterator(Iterator):  # Iterator迭代器对象  重写next()
    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):  # Iterable可迭代对象 重写__iter__
    def __init__(self, cities):
        self.cities = cities

    def __iter__(self):
        print self.__class__.__name__
        return WeatherIterator(self.cities)

# [u"北京", u"上海", u"广州", "长春"]
for x in WeatherIterable([u"北京", u"上海", u"广州", u"长春"]):
    print x

这里写图片描述

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, 100):
    print x

这里写图片描述

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 t <= self.end:
            yield t
            t += self.step

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

for x in reversed(FloatRange(1.0, 4.0, 0.5)):
    print x

这里写图片描述

from itertools import islice

l = [x for x in xrange(20)]
t = iter(l)

# islice(t, 10) 到10
# islice(t, 10, None) 10到结尾
for x in islice(t, 5, 10):  # islice会消耗迭代对象 接着t从10开始
    print x
# -----输出--------
5
6
7
8
9
#-----接着运行------
for x in t:
    print x
# -----输出--------
10
11
12
13
14
15
16
17
18
19

这里写图片描述

# -------使用zip函数--并行-----------
from random import randint

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

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

# -------------使用chain---串行--------

from random import randint
from itertools import chain

e1 = [randint(60, 100) for _ in xrange(39)]
e2 = [randint(60, 100) for _ in xrange(41)]
e3 = [randint(60, 100) for _ in xrange(40)]
e4 = [randint(60, 100) for _ in xrange(42)]

count = 0
for s in chain(e1, e2, e3, e4):
    if s > 90:
        count += 1
print count

猜你喜欢

转载自blog.csdn.net/qq8677/article/details/78113778