欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2 迭代器与生成器

程序员文章站 2024-02-21 14:23:52
...

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进阶笔记
2 迭代器与生成器

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

2 迭代器与生成器

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

2 迭代器与生成器

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

2 迭代器与生成器

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

2 迭代器与生成器

# -------使用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