一迭代器(Iterator)
1.表现形式?
可以调用iter()执行,然后可以返回next方法的对象,称之为迭代器对象。
迭代器协议:对象使用next方法,可以返回迭代中的下一项,或是引发一个StopIteration异常,以终止迭代
可迭代对象:像一些集合数据类型,如list、tuple、dict、set、str等,这些可以作用于for循环的对象
iter()函数注解:
iter(o[, sentinel])
返回一个iterator对象。根据有无第二个参数,对第一个参数的解释相差很大。如果没有第二个参数,o必须是个集合对象,要么支持迭代协议(即 __iter__()方法),要么支持序列协议(即__getitem__()方法,整数参数从0开始)。 如果这些协议都不支持,抛出TypeError。如果有第二个参数sentinel,o必须是个可调用对象。这种情况下返回的迭代,每当调用其next()方法时,将会调用o(不带参数);如果返回值等于sentinel,抛出StopIteration,否则返回该值。
第二种形式的iter()的一个有用的应用就是读一个文件的行,直到读到特定行。下面的例子读一个文件,直到readline()方法返回一个空字符串:
iter()函数有参数情形:
with open('mydata.txt') as fp:
for line in iter(fp.readline, ''):
process_line(line)
iter()无参数情形:
二.生成器(Generator)
1.表现形式?
Python有两种不同的方式提供生成器:
生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
另外生成器是创建迭代器的一种简单而强大的工具,在创建的时候python自动实现迭代器协议。并且合理利用生成器能帮助降低系统资源的消耗。
I:生成器函数
它们写起来就像是正规的函数,只是需要返回数据的时候使用yield语句。每次next()调用时,生成器再恢复它离开的位置(它记忆语句最后一次执行的位置和所有的数据值)。以下示例演示了生成器可以非常简单地创建出来:
要注意的是生成器函数里的yield,可以接收外部传进来的值,或在此中断,打印显示一些东西。如:
## 接收外部值的情形:
def Consume(name):
print '老板还有{}没?'.format(name)
while True:
var=yield
print('好的,{}我要了..').format(var)
def Produce(name):
a=Consume(name)
a.next()
print('喔,再等会,我加急做{}...').format(name)
for i in ['甜的','酸的','辣的']:
print('我做好了{}的{}'.format(i,name))
a.send(i)
Produce('包子')
### 输出
老板还有包子没?
喔,再等会,我加急做包子...
我做好了甜的的包子
好的,甜的我要了..
我做好了酸的的包子
好的,酸的我要了..
我做好了辣的的包子
好的,辣的我要了..
## yield 显示信息的情形
def f(money):
while money>0:
print('兔崽子,来取钱了嘛..')
money -=100
yield '在这老实站着,我去拿下'
print('给拿去,省着点花..')
else:
print('说,你拿了这么多钱干什么去了..')
print('利用yield显示信息的情形... ')
m=f(300)
print m.next()
print('那个你说啥..')
print m.next()
print m.next()
print '哦,不要啊..'
print m.next()
## 输出:
Traceback (most recent call last):
File "F:/Program/pycharm/project/day9/test2.py", line 489, in <module>
print m.next()
StopIteration
利用yield显示信息的情形...
兔崽子,来取钱了嘛..
在这老实站着,我去拿下
那个你说啥..
给拿去,省着点花..
兔崽子,来取钱了嘛..
在这老实站着,我去拿下
给拿去,省着点花..
兔崽子,来取钱了嘛..
在这老实站着,我去拿下
哦,不要啊..
给拿去,省着点花..
说,你拿了这么多钱干什么去了..
II:生成器表达式:
使用列表推导,将会一次产生所有结果,将列表推导的中括号,替换成圆括号,就是一个生成器表达式。使用生成器表达式更紧凑但没有完整定义的生成器用途广泛,而且比同等的列表表示式消耗更少的内存。
备注:从图中也可直观看出可迭代对象与迭代器对象的区别
总结下生成器的几个特点:
A.语法上和常规函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值
B.自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常
C.状态挂起:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行。这个特点可以应用在一些需延时的场合。
参考:
1.https://docs.python.org/2/tutorial/classes.html#iterators
2.https://www.zhihu.com/question/20829330
4.https://segmentfault.com/a/1190000002900850