对于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. 通过openswan基于Azure平台搭建VPN server

    用过Azure的读者都知道,Vnet一直是Azure比较自豪的地方,尤其是VPN,Azure提供了两种VPN以及专线来保证客户数据的安全性,S2S vpn(站点到站点的,基于IPsec的),P2S v ...

  2. postgresql中的CUBE函数

    数据函数简介添加汇总额外信息 数据 --复杂统计函数 CREATE TABLE t3 (color_type varchar(20), in_date varchar(30),color_count ...

  3. html 标签

    CSS : overflow : hidden   --  就是给一个盒子定义了一个显示范围.内部的物体.只有在这个范围内部才会被显示.不然就被隐藏. overflow-x overflow-y 控制 ...

  4. 常用vim插件的安装、使用和管理

      1.Ctags Ctags工具是用来遍历源代码文件生成tags文件,这些tags文件能被编辑器或者其他工具用来快速查找定位源代码中的符号,入变量名,函数名等.比如,tags文件就是Taglist和 ...

  5. word20161216

    object / 对象 object identifier / 对象标识符 offline / 脱机  OLE on-disk catalog / 磁盘目录 on-media catalog / 媒体 ...

  6. _WIN32_WINNT not defined. Defaulting to _WIN32_WINNT_MAXVER (see WinSDKVer.h)

    原文地址::http://blog.csdn.net/xiaolongwang2010/article/details/7550505 相关网帖 1.错误找不到WinsdkVer.h----http: ...

  7. powershell例子

    例子如下: $ErrorActionPreference="Stop" function getlist{ ls D:\tmp2|select name,extension,ful ...

  8. 小的div在大的div中垂直居中

    方法一: 1.代码: <div style="width:200px;height:200px;border:solid blue;position:relative;"&g ...

  9. PSD文件在MAC上和在WINDOWS上的大小有本质区别

    因为偷懒在MAC上的美工,发我的PSD文件,我就直接在上面做了= =后来不知道为什么无论我怎么合并图层.PSD的大小永远都是107M....然后忍无可忍重新画就从107M变成2M.....MAC为什么 ...

  10. SVProgressHUD

    原文:http://cht005288201307234627.iteye.com/blog/1927961 SVProgressHUD和MBProgressHUD效果差不多,不过不需要使用协议,同时 ...