生成器

如果创建一个有很多元素的列表,但是只需要访问前几个元素,后面的元素占着的空间就白白浪费了

在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。

在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法

第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

L = [x * x for x in range(10)]
g = (x * x for x in range(10))
print(L)#
print(g)

可以直接打印出list的每一个元素,但怎么打印出generator的每一个元素

print(next(g))
print(next(g))

如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

generator保存的是算法,比如我要知道计算第四次的值,next要调用四次,这太麻烦了

for n in g:
print(n)

如果要计算很多次,不断调用next实在是太变态了,正确的方法是使用for循环,generator也是可迭代对象,

如果某些算法用列表生成式的for循环无法实现,还可以用函数,比如著名的斐波拉契数列(Fibonacci)

def fib(max):
n,a ,b = 0,0,1#n是用来控制迭代的次数
while n < max:
yield b
a,b = b,a+b
n = n+1
return 'done'

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

函数是顺序执行,遇到return语句或者最后一行函数语句就返回

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,

返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行

def add():
print('step 1')
yield 1
print('step 2')
yield (3)
print('step 3')
yield (5)

在调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:

o = add()
print(next(o))
print(next(o))
print(next(o))

通过next调用时,遇到yield就停下了,再次调用在中断的地方继续往下执行

for n in add():
print(n)

同样的,把函数改成generator后,基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代

要实验for需要把上面三次调用的代码删除,因为三次调用已经把函数全部执行完了,不会再去执行了。

但是用for循环调用generator时,发现拿不到generator的return语句的返回值

如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

g = fib(6)
while True:
try:
x = next(g)
print('g:',x)
except StopIteration as e:
print('Generator return value:',e.value)
break

generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束

注意区分普通函数和generator函数,普通函数调用直接返回结果

generator函数的“调用”实际返回一个generator对象

迭代器

凡是可作用于for循环的对象都是Iterable类型;比如list,tuple,dict,set,str,generator等

判断是否为Iterable类型

from collections import Iterable

print(isinstance([], Iterable))

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

#直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以使用isinstance()判断一个对象是否是Iterator对象,生成器都是Iterator对象

from collections import Iterator
print(isinstance((x for x in range(10)), Iterator))

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

isinstance(iter([]), Iterator)
isinstance(iter('abc'), Iterator)
list=[1,2,3,4]
it = iter(list)
print(next(it))
print(next(it))
#迭代器也可以用常规for语句进行遍历
for x in it:
print('当前计算:',x)#上面调用了两次,所以这边会接着上一次继续下去,只会打印两句,如果上面只
#调用一次,这里会调用三次

小结

凡是可作用于for循环的对象都是Iterable类型   可迭代对象

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象

Python的for循环本质上就是通过不断调用next()函数实现的

比较使用list和generator保存斐波拉契数列运算结果的的区别

通过返回 List 能满足复用性的要求,但是当max函数运行占用的内存会随着max的增大而增大

def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
for n in fab(5):
print(n)

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

yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。

def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 使用 yield
# print b
a, b = b, a + b
n = n + 1
for n in fab(5):
print(n)

Python3学习笔记15-迭代器与生成器的更多相关文章

  1. python3学习笔记10(迭代器和生成器)

    参考http://www.runoob.com/python3/python3-iterator-generator.html 迭代器 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束 ...

  2. python学习笔记四 迭代器,生成器,装饰器(基础篇)

    迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...

  3. Python学习笔记010_迭代器_生成器

     迭代器 迭代就类似于循环,每次重复的过程被称为迭代的过程,每次迭代的结果将被用来作为下一次迭代的初始值,提供迭代方法的容器被称为迭代器. 常见的迭代器有 (列表.元祖.字典.字符串.文件 等),通常 ...

  4. python 3.x 学习笔记6 ( 迭代器 and 生成器 )

    1.迭代器(Iterator):   可以被next()函数调用并不断返回下一个值的对象,成为迭代器:Iterator  可以直接用于for 循环的对象统称为可迭代对象:Iterable 迭代,顾名思 ...

  5. python3学习笔记(6)_iteration

    #python3 学习笔记17/07/10 # !/usr/bin/env python3 # -*- coding:utf-8 -*- #类似 其他语言的for循环,但是比for抽象程度更高 # f ...

  6. Python3学习笔记(urllib模块的使用)转http://www.cnblogs.com/Lands-ljk/p/5447127.html

    Python3学习笔记(urllib模块的使用)   1.基本方法 urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None,  ...

  7. python3学习笔记(7)_listComprehensions-列表生成式

    #python3 学习笔记17/07/11 # !/usr/bin/env python3 # -*- conding:utf-8 -*- #通过列表生成式可以生成格式各样的list,这种list 一 ...

  8. Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法

    Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法 Summary的用法和Group一样简单,分为两步: 启用Summary功能 在Feature标签内,添加如 ...

  9. Python3学习笔记 - 准备环境

    前言 最近乘着项目不忙想赶一波时髦学习一下Python3.由于正好学习了Docker,并深深迷上了Docker,所以必须趁热打铁的用它来创建我们的Python3的开发测试环境.Python3的中文教程 ...

  10. SQL反模式学习笔记15 分组

    目标:查询得到每组的max(或者min等其他聚合函数)值,并且得到这个行的其他字段 反模式:引用非分组列 单值规则:跟在Select之后的选择列表中的每一列,对于每个分组来说都必须返回且仅返回一直值. ...

随机推荐

  1. luogu4267 TamingtheHerd (dp)

    设f[i][j]为让前i天发生j次暴动需要改变的最少的值 则f[i][j]=min{f[k][j-1]+(x[k+1]!=0)+(x[k+2]!=1)+...+(x[i]!=(i-k-1))} $O( ...

  2. spring基于通用Dao的多数据源配置详解【ds1】

    spring基于通用Dao的多数据源配置详解 有时候在一个项目中会连接多个数据库,需要在spring中配置多个数据源,最近就遇到了这个问题,由于我的项目之前是基于通用Dao的,配置的时候问题不断,这种 ...

  3. springcloud的配置文件的读取顺序

    SpringBoot默认支持properties和YAML两种格式的配置文件.前者格式简单,但是只支持键值对.如果需要表达列表,最好使用YAML格式.SpringBoot支持自动加载约定名称的配置文件 ...

  4. textarea 字体限制,超出部分不显示并及时显示还剩字体个数

    1)HTML <textarea class="box" ></textarea > 2)JQ: $(function(){ $(".box&qu ...

  5. kali linux 启动无法自动连接网络问题i

    kali 有一个很大的问题:无法自动连接网咯. 而且,按照网上的方法修改/etc/Network-manager/Network*.conf和/etc/network/interfaces也没有效果. ...

  6. python-requests-proxies判断学习

    # coding:utf8 import requests def prox(): url = 'http://115.159.33.177/images/ip.php' ip_list = [ 'h ...

  7. python基础练习题30道

    1.执行python脚本的两种方式 答:1>可以在python /home/xxxx.py 2>cd /home    ./xxxx.py  因为py脚本里面指定了python解释器的位置 ...

  8. Spark进阶之路-日志服务器的配置

    Spark进阶之路-日志服务器的配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 如果你还在纠结如果配置Spark独立模式(Standalone)集群,可以参考我之前分享的笔记: ...

  9. 安装MACOS操作步骤详解

    安装MACOS操作步骤详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于安装MAC的操作系统其实大家都知道可以让客服帮忙提供软件上的支持,而且苹果客服都很有礼貌呢,而且非常的 ...

  10. 【DS】排序算法的稳定性

    主要的排序算法有八种:直接插入排序,希尔排序(这两种统称为插入排序),冒泡排序,快速排序(这两种统称为交换排序),直接选择排序,堆排序(这两种统称为选择排序),归并排序,基数排序.今天我们就讨论一下它 ...