博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 生成器
阅读量:6731 次
发布时间:2019-06-25

本文共 2955 字,大约阅读时间需要 9 分钟。

生成器可以理解为一种的数据结构,将算法保存,每次计算并返回一个结果,实现了迭代器协议,生成器也是迭代器

生成器有两种表现形式,1)生成器表达式;2)生成器函数

1、生成器表达式

说到生成器表达式,就得先说一下列表推导式   [i for i in range(10)]   ,生成器表达式,就是将 [ ]  改为 (),区别如下所示

1 >>> b = [i for i in range(20)] 2 >>> b 3 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 4  5 >>> b = (i for i in range(20000)) 6 >>> b 7 
at 0x00000185EC6104F8> 8 >>> next(b) 9 010 >>> next(b)11 112 >>> next(b)13 2

生成器表达式优点:省内存,一次只计算返回一结果。 缺点:不知道有几个元素,只能往后遍历,不能向前遍历,且只能整个生成器只能遍历一次

列表推导式优点:可以通过下标获取元素。 缺点:占用内存大

2、生成器函数

生成器函数:在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器函数

我们都知道 return 是函数的返回值,yield 也可以将值返回,我们先看一个简单的生成器函数与普通函数之间的差别

1 >>> def test(): 2 ...     print("_______生成器函数") 3 ...     yield "返回值1" 4 ...     yield "返回值2" 5 ...     yield "返回值3" 6 ... 7 >>> test() 8 
9 >>> t1 = test()10 >>> print(t1.__next__())11 _______生成器函数12 返回值113 >>> print(t1.__next__())14 返回值215 >>> print(t1.__next__())16 返回值317 >>> print(t1.__next__())18 Traceback (most recent call last):19 File "
", line 1, in
20 StopIteration

 可以看到在第7行调用test()函数的时候,并没有执行函数,而是返回了一个生成器对象。在第10行执行 t1.__next__() 才真正的执行了函数,返回 "返回值1",并保存当前的生成器函数的状态。

每执行一次 next(),生成器函数将执行到下一 yield 并将相应的结果返回,直到产生StopIteration异常。

理解了上述过程,就不难理解生成器表达式的原理,next(t1)  等价于  t1.__next__()

def test():    for i in range(10):        yield iprint(test())t2 = test()print(next(t2))print(next(t2))print(next(t2))t3 = (i for i in range(10))print(t3)print(next(t3))print(next(t3))print(next(t3))#输出结果
012
at 0x000001A12D8FF5E8>012

 

3、生成器强调,send()

生成器中还有一个重要的方法  send() 方法,send()  方法可以解决将值传递给生成器函数的问题,具体如下:

1 >>> def test(): 2 ...     print("____start_____") 3 ...     y1 = yield "返回1" 4 ...     print("____生成器函数内:%s" % y1) 5 ...     y2 = yield "返回2" 6 ...     print("____生成器函数内:%s" % y2) 7 ...     yield "返回3" 8 ... 9 >>>10 >>> t1 = test()11 >>> print(t1.__next__())12 ____start_____13 返回114 >>> print(t1.send("a"))15 ____生成器函数内:a16 返回217 >>> print(t1.send("b"))18 ____生成器函数内:b19 返回3

 

在这里第一次获取值的时候,不能用send(),否者会报错,如果一定要用send,则传值None,如下:

>>> t2 = test()>>> t2.send("a")Traceback (most recent call last):  File "
", line 1, in
TypeError: can't send non-None value to a just-started generator>>> t3 = test()>>> t3.send(None)____start_____'返回1'

于send()  不是很理解的可以尝试往下看,下边是我的一些个人理解,不是很准确,我觉得这样会比较好理解一些

我们可以把函数内 第3行   y1 = yield "返回1"  看成两个过程:1)yield "返回1"    2)y1 = receive_from_send()   [并没有这个方法,只是为了理解说明]

这样就可以看到,当执行 send() 时将参数"a" 传递给生成器函数,并在 1)过程停留,传递过去的值没有语句接收,则会出错

所以第一次是不能传值给生成器函数,y1接收到的值为下一次遍历遍历生成器接收的值。

这里也可以也可以在,上上边的代码执行流程可以看出,执行了 14行,y1才会接收到值。

补充一点:每执行一次 1)next(),2)__next(),3)send(),都会在yield语句停留,并保存当前状态,知道直到产生StopIteration异常,结束遍历。

 

通过生成器,实现斐波那契数列

def fib(n):    a, b = 0, 1    while True:        yield b        a, b = b, a + b        if b > n:            returnf1 = fib(100)   #小于 100 的斐波那契数列for i in f1:    print(i,end=" ")#输出结果1 1 2 3 5 8 13 21 34 55 89

 

转载于:https://www.cnblogs.com/yhongji/p/9471795.html

你可能感兴趣的文章
02.input()交互
查看>>
滚动到页面底部继续加载页面其他内容
查看>>
换用代理IP的Webbrowser方法
查看>>
Python爬虫入门(5):URLError异常处理
查看>>
梯度下降算法以及其Python实现
查看>>
LCA(最近公共祖先)——LCA倍增法
查看>>
如何理解*p++
查看>>
pageContext对象的用法
查看>>
临时改变输出数据路径
查看>>
php 关于时区 date gmdate date_default_timezone_set/get 终极答疑
查看>>
dup和dup2函数
查看>>
Java中ArrayList和LinkedList区别及原理分析
查看>>
第十三周项目2-成绩处理
查看>>
Type Conversion
查看>>
GCD Block
查看>>
我的操作系统复习——进程(上)
查看>>
html 复制 有时不显示样式
查看>>
怎么写测试策略
查看>>
2018-2019-1 20165231 《信息安全系统设计基础》第四周学习总结
查看>>
jar包的一天
查看>>