对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧。

可迭代对象

当你创建一个列表的时候,你可以一个接一个地读取其中的项。一个接一个地读项就叫做迭代

>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3

mylist就是一个可迭代对象。你使用列表推导式时,就创建了一个列表,也就是一个可迭代对象:

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4

任何可以用“for...in...”操作的事物都是可迭代对象;列表,字符串,文件……

这些可迭代对象很方便,因为你可以随意地访问它们,但是你把所有的值都保存在内存中。如果你有大量的数据的话,这就不是你想要的了。

生成器

生成器是迭代器,但是你只可以对它们进行一次迭代。这是因为你没有在内存中存储所有数值,它们动态地生成值

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4

跟上面的例子基本一样,除了用()代替了[]。但是,你不能第二次执行for i in mygenerator,因为生成器只能使用一次;它计算出0,然后忘掉0并计算1,最后是计算4,一个接一个地进行。

Yield

Yield是一个像return一样的关键字,只不过函数返回的是一个生成器:

>>> def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = createGenerator() # 创建一个迭代器
>>> print(mygenerator) # mygenerator是一个对象!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
... print(i)
0
1
4
>>> for i in mygenerator:
print(i) >>>

这个例子里的生成器没什么用,但是如果你知道你的函数会返回大量的数据,而你只需要对这些数据读取一次时,那就变得很有用了。

要掌握yield你必须理解当你访问函数的时候,你写在函数体中的代码并没有执行。这个函数只是返回了迭代器对象,这一点很微妙。

然后,每次for语句使用生成器的时候,你的代码就会运行。

然后是最难的部分:

for语句第一次调用从你的函数中创建的迭代器对象时,它就会运行你函数中的代码,从开始一直到它碰见yield,然后它就返回这个循环中的第一个值。之后,每一次的调用都会再一次运行你写在函数里的循环,然后返回下一个值,直到没有值可以被返回。

一旦函数运行但是没有再碰到yield,生成器就被认为是空的。这可能是因为循环已经结束了,或者因为不再满足if/else条件了。

控制生成器耗尽

>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(self):
... while not self.crisis:
... yield "$100"
>>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # crisis is coming, no more money!
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business
>>> for cash in brand_new_atm:
... print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...

这个在很多方面都有用,比如控制对某个资源的访问。

Itertools,好帮手

itertools模块包含操作可迭代对象的特殊函数。想要复制一个生成器?连接两个生成器?把嵌套列表中的数据整理到一个列表中?不创建另一个列表就直接Map/Zip?

那就import itertools

例子?那我们看看4马比赛中所有可能的到达顺序(全排列):

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]

理解迭代的内部机制

迭代是一个暗含可迭代对象(实现了__iter__()方法)和迭代器(实现了__next__()方法)的过程。可迭代对象是任何你可以从中得到迭代器的对象。迭代器是可以让你对可迭代对象进行迭代的对象。

更多信息请参考how does the for loop work

Python中的生成器与yield的更多相关文章

  1. python中的生成器函数是如何工作的?

    以下内容基于python3.4 1. python中的普通函数是怎么运行的? 当一个python函数在执行时,它会在相应的python栈帧上运行,栈帧表示程序运行时函数调用栈中的某一帧.想要获得某个函 ...

  2. Python学习-39.Python中的生成器

    先回顾列表解释 lista = range(10) listb = [elem * elem for elem in lista] 那么listb就将会是0至9的二次方. 现在有这么一个需求,需要存储 ...

  3. python中的生成器(二)

    一. 剖析一下生成器对象 先看一个简单的例子,我们创建一个生成器函数,然后生成一个生成器对象 def gen(): print('start ..') for i in range(3): yield ...

  4. 深入理解Python中的生成器

    生成器(generator)概念 生成器不会把结果保存在一个系列中,而是保存生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常结束. 生成器语法 生成器表达式: 通列表解 ...

  5. python迭代器与生成器及yield

    一.迭代器(itertor) 1.可迭代: 在Python中如果一个对象有__iter__()方法或__getitem__()方法,则称这个对象是可迭代的(iterable). 其中__iter__( ...

  6. 聊聊Python中的生成器和迭代器

    Python中有两个重要的概念,生成器和迭代器,这里详细记录一下. 1. 生成器 什么是生成器呢? 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...

  7. python中的生成器(一)

    我们先考虑一个场景: 有个情景需要循环输出1——10. 这里给两种方法: list1 = [1,2,3,4,5,6,7,8,9,10] for i in list1: print(i) for i i ...

  8. python中的生成器(generator)总结

    1.实现generator的两种方式 python中的generator保存的是算法,真正需要计算出值的时候才会去往下计算出值.它是一种惰性计算(lazy evaluation). 要创建一个gene ...

  9. python学习之【第十三篇】:Python中的生成器

    1.为什么要有生成器? 在Python中,通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅 ...

随机推荐

  1. 信息安全比赛总结(21ic转帖)

    我们的题目是基于这个ZedBoard的__视频流的人脸识别识别的算法采用的是PCA,,但是在后期的调试和实验中发现,,PCA的效果很容易受到环境,比如光照强度,背景,摄像头像素等影响:如果后期的改进的 ...

  2. 他山之石——vs2013 安装与部署及程序打包

    C#打包需要这个:InstallShield 2013 Limited Edition for Visual Studio  .下载地址: InstallShield 2013 Limited Edi ...

  3. MySQL 权限与安全

    一.MySQL权限系统通过两个阶段进行认证: (A) 对用户进行身份认证,IP地址和用户名联合, (B) 对合法用户赋予相应权限,权限表在数据库启动的时候载入内存中. 二.在权限的存取过程中,会用到& ...

  4. HTML5存储之 indexedDB

    IndexeDB是HTML5 重要的一部分,它是一种轻量级的NOSQL数据库.对创建具有丰富本地存储数据的数据密集型的离线HTML5 Web 应用程序很有用. IndexedDB是为了能够在客户端存储 ...

  5. Eclipse的快捷键

    Ctrl+Shift+L调出eclipse的所有快捷键 不定期更新2016#8#19 如何配置快捷键:windown-preferences-General-key 一些操作  Ctrl+D   删除 ...

  6. LRU LFU FIFO 转载

    -------------------------------------->href--------------------------> http://blog.chinaunix.n ...

  7. apache 虚拟机配置

    <VirtualHost *:80> DocumentRoot /www/htdocs/caipiao ServerName www.aaa.com ServerAlias aaa.com ...

  8. 关于清除arp 缓存的那点事儿

    在Linux下,清除arp缓存表,例如: arp -d 10.0.3.6 我们可以用上面这条命令清除某一条记录,也可以用 arp -n |awk '/^[1-9]/{print "arp - ...

  9. delphi tidhttp 超时设置无效的解决方法

    现在delphi都发布到xe8了,tidhttp还有缺陷,那就是超时设置在没有网络或者连不上服务器的时候是无效的,不管你设置为多少都要10-20秒.connectTimeout和readTimeout ...

  10. Gitlab完美安装【CentOS6.5安装gitlab-6.9.2】

    摘要: 拆腾了几天,终于在今天找到了快速安装Gitlab的方法.CentOS6.5安装gitlab-6.9.2 参考网址:https://gitlab.com/gitlab-org/omnibus-g ...