Python进阶教程,生成器、迭代器一文掌握( 二 )

  • 保存当前运行状态 , 暂停执行
  • 将 yield 关键字 后面表达式的值 , 作为返回值返回 , 可理解为起到了return的作用
  • 生成器的作用
    1. 通过列表生成式 , 我们可以直接创建一个列表 , 但是 , 受到内存限制 , 列表容量肯定是有限的 。
    2. 而且 , 创建一个包含100万个元素的列表 , 不仅占用很大的存储空间 , 如果我们仅仅需要访问前面几个元素 , 那后面绝大多数元素占用的空间都白白浪费了 。
    3. 所以 , 如果列表元素可以按照某种算法推算出来 , 那我们是否可以在循环的过程中不断推算出后续的元素呢?
    4. 这样就不必创建完整的list , 从而节省大量的空间 。 在Python中 , 这种一边循环一边计算的机制 , 称为生成器:generator 。
    生成器工作原理
    1. 生成器是这样一个函数 , 它记住上一次返回时在函数体中的位置 。
    2. 对生成器函数的第二次(或第 n 次)调用跳转至该函数中间 , 而上次调用的所有局部变量都保持不变 。
    3. 生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造中的位置 。
    4. 生成器是一个函数 , 而且函数的参数都会保留 。
    5. 迭代到下一次的调用时 , 所使用的参数都是第一次所保留下的 , 即是说 , 在整个所有函数调用的参数都是第一次所调用时保留的 , 而不是新创建的
    yield生成器运行机制在Python中 , yield就是这样的一个生成器 。
    1. 当你问生成器要一个数时 , 生成器会执行 , 直至出现 yield 语句 , 生成器把yield 的参数给你 , 之后生成器就不会往下继续运行 。
    2. 当你问他要下一个数时 , 他会从上次的状态开始运行 , 直至出现yield语句 , 把参数给你 , 之后停下 。 如此反复
    3. 在python中 , 当你定义一个函数 , 使用了yield关键字时 , 这个函数就是一个生成器
    4. 它的执行会和其他普通的函数有很多不同 , 函数返回的是一个对象 , 而不是你平常所用return语句那样 , 能得到结果值 。 如果想取得值 , 那得调用next()函数
    5. 每当调用一次迭代器的next函数 , 生成器函数运行到yield之处 , 返回yield后面的值且在这个地方暂停 , 所有的状态都会被保持住 , 直到下次next函数被调用 , 或者碰到异常循环退出 。
    为什么说生成器是一种迭代器?Python 判断一个对象是否是迭代器的标准是看这个对象是否遵守迭代器协议, 判断一个对象是否遵守迭代器协议主要看两个方面:
    1. 对象首先得实现 iter 和 next 方法
    2. 其次iter 方法必须返回它自己
    而生成器恰好满足了这两个条件(可以自己写个生成器 , 然后调用生成器的这两个方法试试) 。 我们平常还会经常碰到另外一个概念:可迭代对象 。 可迭代对象就是可迭代的对象 , 可迭代的对象就是说我们可以从这个对象拿到一个迭代器 。 在 Python 中 , iter 方法可以帮我们完成这个事情 , 也就是说 , 可迭代对象和迭代器满足这样一个关系:iter(iterable) -> iterator 。
    在 Python 中 , list 是个可迭代对象 , 所以我们经常会写这样的代码:
    l = [1, 2, 3]for element in l: print(element)但你想过为什么我们可以这么写吗?为啥在 c 语言里面 , 我们访问数组元素的时候 , 必须要通过 index?
    因为:list 是个可迭代对象 , 我们在 Python 中使用 for … in 时 , Python 会给我们生成一个迭代器对象 , 而如上所说:迭代器是个数据流 , 它可以产生数据 , 我们一直从里面取数据就好了 , 而不需要我们在代码中维护 index , Python 已经通过迭代器给我们完成了这个事情 。
    构建生成器:将列表推导式的方括号 改为 小括号