生成器

定义:使用了 yield 的函数被称为生成器(generator)。

和普通函数的区别:调用一个生成器函数,返回的是一个迭代器对象。生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

优点:生成器按需每次只生成一个数据,而不用一下子生成所有元素。节省了cpu和内存

协程:pyhton中当协程执行到yield关键字时,会暂停在那一行,等到主线程调用send方法发送了数据,协程才会接到数据继续执行。但是,yield让协程暂停,和线程的阻塞是有本质区别的。协程的暂停完全由程序控制,线程的阻塞状态是由操作系统内核来进行切换。因此,协程的开销远远小于线程的开销。

斐波那契数列举例:

def fab(max):
    n, a, b = 1, 0, 1
    while a <= max:
        yield a
        a, b = b, a + b
        n = n + 1
fab_generator = fab(5)
print(fab_generator)
#<generator object fab at 0x000001A02272C5C8>
for n in fab(5):  # 类似a=fab(5), next(a),next(a)...
    print(n)
0
1
1
2
3
5

迭代器

迭代:类似list, tuple, str,dict, str 等类型的数据可以通过循环依次拿到数据并使用,这个过程称为遍历也称迭代。

迭代对象:包含__iter__(返回迭代器本身)

迭代器:包含__iter__和__next__

迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。迭代器最核心的功能就是可以通过___iter__() 只会被调用一次,而 _next_() 会被调用 n 次,直到出现StopIteration异常

优点:迭代器按需每次只取一个数据,解决了内存一次性放不下所有数据的问题。

class Fab(object):

    def __init__(self, max):
        self.max = max
        self.n, self.a, self.b = 1, 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.n <= self.max:
            r = self.a
            self.a, self.b = self.b, self.a + self.b
            self.n = self.n + 1
            return r
        raise StopIteration()

for n in Fab(5):   #等价于调用a=Fab(5) print(next(a))
    print(n)

生成器与迭代器的区别

生成器是迭代器的一种实现,所有生成器都是迭代器,因为生成器完全实现了迭代器接口,迭代器用于从集合中取出元素,而生成器用于“凭空”生成元素,生成器相较于迭代器更为简洁,它能极大程度的简化代码,使得执行流程更为清晰。

迭代器需要我们定义一个类来实现相关的方法才能构造一个灵活的迭代器,而生成器则只需要在普通的函数中加入一个yield关键字,yield 语句的作用就是把一个函数变成一个生成器(generator),生成器的出现使得python能类似于协同程序工作