迭代器和生成器总结

迭代器:


是一个抽象的概念,任何对象,如果它的类有 next 方法和 iter 方法返回自己本身,对于 string、list、dict、tuple 等这类容器对象,使用 for 循环遍历是很方便的。在后台 for 语句对容器对象调用 iter()函数,iter()是 python 的内置函数。iter()会返回一个定义了 next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是 python 的内置函数。在没有后续元素时,next()会抛出一个 StopIteration 异常。


关于iter()和next():


1、iter(iterable)函数是把可迭代对象的迭代器取出来,内部是调用可迭代对象的__iter__方法,来取得迭代器的
2、next(iterator)函数是通过迭代器取得下一个位置的值,内部是调用迭代器对象的__next__方法,来取得下一个位置的值
注意: 
当我们已经迭代完最后一个数据之后,再次调用next()函数会抛出StopIteration的异常,来告诉我们所有数据都已迭代完成,不用再执行next()函数了。
所以:
我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。
结论: 
一个实现了__iter__方法和__next__方法的对象,就是迭代器,迭代器同时也是一个可迭代对象


示例代码:

class FibIterator(object):
    """斐波那契数列迭代器"""

    def __init__(self, n):
        # 记录生成fibonacci的数列的个数
        self.n = n
        # 记录当前遍历的下标
        self.current_index = 0
        # 记录fibonacci数列前面的两个值
        self.num1 = 0
        self.num2 = 1

    def __next__(self):
        """被next()函数调用来获取下一个数"""
        if self.current_index < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            self.current_index += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        """迭代器的__iter__返回自身即可"""
        return self


if __name__ == '__main__':
    fib = FibIterator(10)
    for num in fib:
        print("  ", num, end="")

# 运行结果: 0 1 1 2 3 5 8 13 21 34

生成器(Generator):


是创建迭代器的简单而强大的工具。生成器是一种特殊的迭代器,它比迭代器写起来更加优雅,它们写起来就像是正规的函数,只是在需要返回数据的时候使用 yield 语句。每次 next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)

最简单的生成器就是把一个列表生成式的[ ]改成( )
例如:g = (x*2 for x in rang(5)),就是一个生成器
另外一种生成器的创建方法就是这一个函数里面加yield:
例如把上面的斐波那契函数改写成生成式如下:

def fib(n):
    current_index = 0
    num1, num2 = 0, 1
    while current_index < n:
        # print(num1) # 打印斐波那契数列
        """
         1. 假如函数中有yield,则不再是函数,而是生成器
         2. yield 会产生一个断点
         3. 假如yield后面紧接着一个数据,就会把数据返回,
            作为next()函数或者for ...in...迭代出的下一个值
        """
        yield num1
        num1, num2 = num2, num1 + num2
        current_index += 1

if __name__ == '__main__':
    # 假如函数中有yield,则不再是函数,而是一个生成器
    gen = fib(10)

    #  生成器是一种特殊的迭代器
    for num in gen:
        print(num)

# 运行结果: 0 1 1 2 3 5 8 13 21 34

通过代码可以很直观看出生成器更优雅更省代码

扫描二维码关注公众号,回复: 2546608 查看本文章

yield其实就是保存当前程序执行状态。你用 for 循环的时候,每次取一个元素的时候就会计算一次。用 yield 的函数叫 generator,和 iterator 一样,它的好处是不用一次计算所有元素,而是用一次算一次,可以节省很多空间。generator每次计算需要上一次计算结果,所以用 yield,否则一 return,上次计算结果就没了,简单来说一个函数里面加了yield就是生成器。
还有我们除了可以使用next()函数来唤醒生成器继续执行外,还可以使用send()函数来唤醒执行。使用send()函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。

总结:


1、使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
2、yield关键字有两点作用:
 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用
3、可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)

区别:


生成器能做到迭代器能做的所有事,而且因为自动创建了 iter()和 next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出 StopIteration 异常。

猜你喜欢

转载自www.cnblogs.com/longguoliang/p/9419322.html