#原创,转载请先联系

在学习生成器之前,必须先了解一下迭代器。因为生成器就是一种特殊的迭代器,而且生成器用起来更加优雅。

迭代器的详解可以参考我的另一篇博文:https://www.cnblogs.com/chichung/p/9537969.html

先说一种比较简单的生成器,通过例子慢慢来体会什么是生成器。

# 列表生成式
L = [x for x in range(5)]
print(L) #简单的生成器
G = (x for x in range(5)) # G就是一个生成器,也是一个迭代器,迭代器也是可迭代对象,所以这个G也可以说是可迭代对象
print(next(G))
print(next(G))
print(next(G))
print(next(G))
print(next(G)) 输出:
[0, 1, 2, 3, 4]
0
1
2
3
4

把列表生成器的[]改为()就变成一个简单的生成器。由上面的例子,我们大概可以知道,生成器就是一个迭代器,把数据一个一个拿出来,可以减少内存的负担。

那么,yield又是一个什么东西呢?为什么说他优雅呢?

当我们写的代码输出的结果,想一个一个出来。有两种常用的方法:

方法1.我们可以创建一个迭代器类,然后把代码写进类里,用类来创建一个可迭代对象,然后用next()函数一个一个把结果迭代出来。

方法2.我们可以用代码函数的合适位置加上yield,这时候这个函数就变成一个生成器了,不需要再创建一个迭代器类,不需要再写__iter__,__next__方法了。这样一来不是很方便,很优雅吗?哈哈哈哈~

口说无凭,下面我们2个方法都做一下,让你们体会一下:

我们做一个斐波那契的数列生成器。斐波那契数列的第一个数是0,第二个数是1,第三个数是第一、二个数相加,第四个数是第二、三个数相加......

方法1:

class FeiboIterator():
def __init__(self):
self.a = 0
self.b = 1 def __iter__(self):
return self def __next__(self):
num = self.a
self.a,self.b = self.b,self.a+self.b
return num iterator = FeiboIterator()
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator)) 输出:
0
1
2
3
5
8
13

是不是很麻烦?又要初始化,又要写__iter__和__next__魔方方法。

方法2:

def feibo():
a = 0
b = 1
while True:
yield a # 假如yield后面紧接着一个数据,就会把数据返回,作为next()函数或者for ...in...迭代出的下一个值
a,b = b,a+b generator = feibo() print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator))
print(next(generator)) 输出:
0
1
1
2
3
5
8
13

看!只有6行代码,是不是很elegant?关于这个程序是怎么运行的?yield是怎么运作的?我们等下就讲,现在需要注意几点:

1.上面代码的红色字那里!假如yield后面紧接着一个数据,就会把数据返回,作为next()函数或者for ...in...迭代出的下一个值。

2.假如函数中有yield,就不再是函数。而是一个能返回生成器的函数!注意!是返回,这个函数并不是一个生成器。(修正:这句话发现有错误,这个函数也是一个生成器)

3.拿到函数的生成器后,可以和迭代器一样,用next()函数获得下一个值。

好了,该来理解一下yield是怎么运作的了!

1.第一次唤醒生成器时,是从函数的起始位置开始,直到遇到yield,就会暂停函数,挂起函数。
2.第二次唤醒生成器时,是从yield断点处开始,直到又遇到yield。
3.当生成器已经没有yield,再使用next,则抛StopIteration异常。

然后,我们来理一下上面用yield写的代码。

第一次用next()唤醒生成器时,从函数的开头开始运行,遇到yield a,返回a,然后暂停函数,并记住函数是运行到这个位置的。

第二次唤醒生成器,从yield a断点处开始,然后a,b开始赋值,while True循环又遇见yield a,返回a,然后暂停函数,并记住函数是运行到这个位置的。

下面唤醒多少次都是这个道理,但是由于这个函数是死循环,所以不会没有yield,也就不会抛出StopIteration异常。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

其实yield还能接受值,用send方法进行传入。代码体会一下:

def gg():
i = 1
while True:
recv = yield i
print("接收到一个值:",recv)
i += 1 generator = gg() print(next(generator))
print(generator.send(""))
print(generator.send("")) 输出:
1
接收到一个值: 456
2
接收到一个值: 789
3

实现过程和上面的例子一样。

要懂得的是,yield = a,会返回a。

b = yield,会把yield接收的值赋值给b。

python中的yield生成器详解的更多相关文章

  1. Python中的高级数据结构详解

    这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...

  2. Python中格式化format()方法详解

    Python中格式化format()方法详解 Python中格式化输出字符串使用format()函数, 字符串即类, 可以使用方法; Python是完全面向对象的语言, 任何东西都是对象; 字符串的参 ...

  3. python中的tcp示例详解

    python中的tcp示例详解  目录 TCP简介 TCP介绍 TCP特点 TCP与UDP的不同点 udp通信模型 tcp客户端 tcp服务器 tcp注意点   TCP简介   TCP介绍 TCP协议 ...

  4. Python中的yield生成器的简单介绍

    Python yield 使用浅析(整理自:廖 雪峰, 软件工程师, HP 2012 年 11 月 22 日 ) 初学 Python 的开发者经常会发现很多 Python 函数中用到了 yield 关 ...

  5. python中的 zip函数详解

    python中zip()函数用法举例 定义:zip([iterable, ...]) zip()是Python的一个内建函数,它接受一系列可迭代的对象作为参数,将对象中对应的元素打包成一个个tuple ...

  6. python中的buildin函数详解(第一篇)

    这会是很长的一个帖子,因为我打算从python最基础的东西开始,尝试去完全的掌握它,buildin中有一些常用的函数比如 abs, open, setattr, getattr, 大家都很了解他们的用 ...

  7. python中的builtin函数详解-第二篇

    classmethod(function) 这里不过多说明这个builtin方法的具体用法,python的文档和help函数已经给了这个方法充足的使用说明,所以我这里要说的时关于 classmetho ...

  8. python中的Queue(队列)详解

    一.Queue简介 python中的队列分类可分为两种: 1.线程Queue,也就是普通的Queue 2.进程Queue,在多线程与多进程会介绍. Queue的种类: FIFO:  Queue.Que ...

  9. Python中标准模块importlib详解

    1 模块简介 Python提供了importlib包作为标准库的一部分.目的就是提供Python中import语句的实现(以及__import__函数).另外,importlib允许程序员创建他们自定 ...

随机推荐

  1. HDU 4757 Tree(可持久化字典树)(2013 ACM/ICPC Asia Regional Nanjing Online)

    Problem Description   Zero and One are good friends who always have fun with each other. This time, ...

  2. java获得采集网页内容的方法小结

          为了写一个java的采集程序,从网上学习到3种方法可以获取单个网页内容的方法,主要是运用到是java IO流方面的知识,对其不熟悉,因此写个小结. import java.io.Buffe ...

  3. [译]在Python中如何使用额enumerate 和 zip 来迭代两个列表和它们的index?

    enumerate - 迭代一个列表的index和item <Python Cookbook>(Recipe 4.4)描述了如何使用enumerate迭代item和index. 例子如下: ...

  4. winform 外部组件发生异常

    问题描述.先前程序运行可以正常,但是突然这次调试就弹出此异常: 解决方法:1.本次调试是不是重新生成解决方案了?应该是因为之前的解决方案删了,把引用的dll(包含此dll关联的dll)自动删掉: 2. ...

  5. 《SQL入门经典》总结

    <SQL入门经典>这本书从考试前就开了个头,一直到前两天才看完,拉的战线也够长的.放假来了,基本上什么内容都不记得了.好不容易看完了,就赶紧总结一下吧! 该书分为两大部分,第一部分是第1~ ...

  6. javascript中将整数添加千位符号

    如果num是整数的话,将其转换成带千位符号的字符串: Number(num).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' +  ','); 另 ...

  7. AtCoder Grand Contest 025 Problem D - Choosing Points

    题目大意:输入$n,d1,d2$,你要找到$n^2$个整点 x, y 满足$0 \leqslant x, y<2n$.并且找到的任意两个点距离,既不是$\sqrt{d1}$,也不是 $\sqrt ...

  8. 对C++ templates类模板的几点补充(Traits类模板特化)

    前一篇文章<浅谈C++ templates 函数模板.类模板以及非类型模板参数>简单的介绍了什么是函数模板(这个最简单),类模板以及非类型模板参数.本文对类模板再做几点补充. 文章目录1. ...

  9. [Leetcode] Reorder list 重排链表

    Given a singly linked list L: L 0→L 1→…→L n-1→L n,reorder it to: L 0→L n →L 1→L n-1→L 2→L n-2→… You ...

  10. fis难用的地方

    1. 刷新不同步,刷新的结果是前一次的修改结果2. 刷新时间非常长3. 有些代码打包不兼容,例如tween这个库,有函数yoyo:function yoyo(yoyo){}的形式,不能正确打包,会报[ ...