Python的迭代器和生成器详解

こ雲淡風輕ζ 提交于 2019-12-03 03:31:24

我们说Python是一门高效的语言,在于它内置的一些变量访问模式——其中迭代器和生成器,可以算是Python的特色了,功能强大,用起来很爽


迭代器(Iterator)

迭代器简介

迭代器(iterator)也成游标(cursor),是实现了迭代操作的对象,通过迭代器开发人员可以不同知道容器内部的详细情况而在容器(如链表、矩阵)上进行遍历

它是一个带状态的对象;在调用next()函数的时候返回容器的下一个值,任何实现了__iter()__和__next()__方法的对象都是迭代器,__iter()__返回迭代器自身,__next()__返回容器的下一个值,如果容器没有更多的元素,就抛出StopIteration异常——所以说,迭代器是一个实现了工厂模式的对象

迭代器的好处总结起来八个字:延迟计算,按需调用

Python内置的iter()函数用于生成一个迭代器,其中括号内参数可以是字符串、列表、或者元祖(它们都是可迭代对象,即可以用for..in语句进行遍历的对象)

i = iter("Hello")

使用next()函数对迭代器进行遍历

>>> next(i)
H
>>> next(i)
e

itertools模块

Python内指了一个很有意思的支持迭代的工具模块:itertools,该模块提供的全部是处理迭代功能的函数,它们的返回值不是list而是迭代对象,只有用for循环进行迭代才能对其中的元素进行计算等操作

使用itertools可以实现无限序列

import itertools

natures = itertools.count(1)    #nature是一个迭代器,从1开始每次生成一个新的自然数
for n in natures:
    print(n)    #不断打印自然数,直到按ctrl+C结束

cs = itertools.cycle('ABC')     #cs是一个迭代器器,从A开始循环打印A、B、C
for c in cs:
    print(c)    #不断打印A、B、C、A、B……

ns = itertools.repeat('A', 10)      #ns是一个迭代器,支持对于元素A做10次操作
for n in ns:
    print(n)    #打印10次A

无限序列虽然可以无限制的打印下去,但是通常通过takewhile()等函数根据条件判断来截取一个有限序列

natures = itertools.count(1)
ns = itertools.takewhile(lambda x: x<=10, natures)
for n in ns:
    print(n)    #打印出1~10

生成器(Generator)

生成器是特殊的迭代器,是一类特殊的函数(或表达式)

一般来说有两类生成器:1)生成器函数,2)生成器表达式

生成器函数:和普通的函数不同在于使用yield关键字而非return关键字返回结果,yield一次返回一个结果,在每两次调用之间挂起函数的状态以便下次调用时从上次离开的地方继续执行

生成器表达式:类似于列表推导,使用()而非[]构建一个生成器,每次返回按需求产生结果的一个对象

生成器函数

生成器函数的关键就在于yield关键字

def g(n):
    for i in range(n):
        yield i**2

for item in g(5):
    print(item, end=" ")

这里写图片描述

生成器表达式

类比列表推导学习生成器表达式

还是上面的那个例子,我们说生成器表达式在某种程度上可以看成是生成器函数的轻巧版本

>>> g = (x**2 for x in range(5))
>>> for i in g:
    print(i,end=" ")

这里写图片描述

使用生成器的好处是每次返回一个结果,特别是在处理大量数据的时候可以有效的减少内存占用(说到底就是迭代器的好处)


使用迭代器和生成器打印菲波拉契数列

"""最简单、不动脑子的想法:使用递归"""

def fib(n):
    if n==1 or n==2:
        return 1
    else:
        return fib(n-1) + fib(n-2)

m = fib(10)

for i in m:
    print(i, end=" ")

这里写图片描述

"""使用for循环交换tuple中的值"""

def fib(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a+b
        yield a    #yield关键字,说明是生成器

m = fib(10)

for i in m:
    print(i, end=" ")

这里写图片描述

"""定义一个类,定制迭代器对象"""

class Fib(object):

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

    def __iter__(self):
        return self    #迭代器自身也是一个支持迭代操作的可迭代对象,故每次迭代操作后返回自身

    def __next__(self):
        self.a, self.b = self.b, self.a+self.b
        if self.a > self.limit:    #记住,Pythonic的代码if语句是不加括号的
            raise StopIteration
        return self.a

    def __repr__(self):
        return str(self.a)

m = Fib(60)    #这里传入的limit参数不是执行爹迭代次数而是元素大小的上限,为了和前面达成一致这里我使用60作为限制条件

for i in m:
    print(m, end=" ")   

这里写图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!