生成器、迭代器
1、列表生成式
a = [i**2 for i in range(10)]
a为 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
2、生成器
定义:一边循环一边计算后面元素的机制,称为生成器(generator)。
生成器创建方法
1、g = (i**2 for i in range(10))
打印generation元素,需要用到next()方法
next(g) 一次只能打印一个,要想再次打印就在next(g)
当next(g)打印完最后一个元素后,在使用next(g),解释器则会报错。
可以用for循环进行遍历,将所有元素都打印出来,也可以打印出自己需要的元素
for i in g:
if i > 10
print(i)
2、用函数来创建生成器,使用yield
以斐波那契数列举例 0,1,1,2,3,5,8,13,21,34,55...
当不使用生成器的:
def fibo(n): before,now = 0, 1 sum = 0 count = 0 while count < n: sum = before + now before = now now = sum count += 1 print(before)
如果使用生成器的话,只需要将print(before)变成yield before就可以了
def fibo(n): before,now = 0, 1 sum = 0 count = 0 while count < n: sum = before + now before = now now = sum count += 1 yield before g_fibo = fibo(8)
调用生成元素可以用g_fibo.__next__()
当使用一次g_fibo.__next__(),函数运行就会暂停在yield位置,你就可以做其他的事情,当再次遇到g_fibo.__next__(),函数就会又开始执行,函数不断的暂停,开始。
用生成器模拟并发编程
import time def consumer(name): print("{0}准备开始吃东西".format(name)) while True: meat = yield # 将外面传过来的值赋值给meat print("肉{0}来了,肉被{1}吃了".format(meat, name)) c1 = consumer("xu1") c2 = consumer("xu2") c1.__next__() c2.__next__() print("--------------大帅哥要开始做肉啦----------") for i in range(10): time.sleep(1) print("做了2盘肉") c1.send(i) # 将 i 传到yield处 c2.send(i)
调用send(x)给生成器传值时,必须确保生成器已经执行过一次next()调用, 这样会让程序走到yield位置等待外部第2次调用。
3、迭代器
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable,可迭代的意思就是可遍历、可循环。
可以使用isinstance()判断一个对象是否是Iterable对象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
--------借鉴于old_boy(老男孩教育)-------------------