一、生成器
通过一定算法,生成一些列的值.。边生成边运算,达到节省资源的目的。
生成器:generator
a.生成器在调用的时候,才生成相应的数据
b.生成器只记录当前的位置 只有.next()这一个方法
c.生成器当元素打印结束后就停止运行
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
list1 = [i*2 for i in range(10)]
print(list1)
list2 = (i*2 for i in range(10))
print(list2)
结果为
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
<generator object at 0x0000025490BC1C78>
第一个打印的就是一个列表
第二个打印的就是生成器的内存地址对象
生成器中的元素 打印出generator的每一个元素
可以用.next()方法 一个一个打印出来
list2 = (i*2 for i in range(10))
print(list2)
print(list2.__next__())
print(list2.__next__())
#调用几次方法 就打印几个生成器中的元素
生成器保存的是算法,每次调用.next(),就能计算出下一个元素的值,知道计算出最后一个元素,没有更多的元素时,抛出StopIteration的错误
一直用这个方法也不太好
因为生成器也是可迭代对象,所以可以用for循环
list2 = (i*2 for i in range(10))
print(list2)
for i in range(9):
print(list2.__next__())
生成器非常强大,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
比如:著名的斐波拉契数列除第一个和第二个数外,任意一个数都可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21, 34, …
斐波拉契数列
def fib(max):
n,a,b = 0,0,1
while n < max:
print(b)
a,b = b,a+b
n = n+1
return 'down'
fib(10)
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了
yield b 保存了函数的中断状态,并返回值
def fib(max):
n,a,b = 0,0,1
while n < max:
yield b
a,b = b,a+b
n = n+1
return 'down'
c = fib(10)
print(c.__next__())
生成器
用途:"协程"的效果—“单线程下的并行效果” | 一步io的雏形(nginx)
“生产者—消费者模型”
简单的生产者消费者模型
对于生成器的对象:
c.next() #唤醒生成器,不执行后面的程序 执行一些程序就会停止
c.send(‘massage’) #唤醒生成器,执行后面的程序
import time
#消费者
def consumer(name,):
print('[%s] 开始消费了'%name)
while True:
messages = yield
print('消息:[%s],被[%s]接收了'%(messages,name))
c = consumer('leilei') #函数没有运行
c.__next__() #没有执行后面的程序、生成器
c.send('明天不上课') #唤醒生成器、执行了后面的程序
结果为:
[leilei] 开始消费了
消息:[明天不上课],被[leilei]接收了
生产者消费者
import time
#消费者
def consumer(name,):
print('[%s] 开始消费了'%name)
while True:
messages = yield
print('消息:[%s],被[%s]接收了'%(messages,name))
# c = consumer('leilei')
# c.__next__()
# c.send('明天不上课')
#生产者
def producer(name):
C1 = consumer('leilei') #没有运行
C2 = consumer('shitou') #没有运行
C3 = consumer('tongtong') #没有运行
C1.__next__()
C2.__next__()
C3.__next__()
print('%s开始生产消息了...'%name)
for i in range(10):
time.sleep(1)
# i = '明天不上课'
# print('明天不上课')
C1.send(i)
C2.send(i)
C3.send(i)
producer('gaohaha')
#这个跟上面的调用一样的 只不过生产者生产的消息 消费者在接受的时候 都停了一秒
二、迭代器
基础概念:(理解)
底层实现的原理、概念
可迭代的对象:
可以直接作用于for循环的对象:
1)集合的数据类型(str,list[],dict{},set,tuple())
2)生成器 包括生成器和带yield的生成器函数
这里要知道可迭代对象 ==!迭代器
迭代器:
可以被_next_()函数调用并且可以返回一个值的对象 --> 迭代器
1.判断是否为可迭代对象
需要导入一个Iterable的模块
from collections.abc import Iterable
list = [] #列表
tuple = () #元组
str = '' #字符串
dict = {} #字典
def fib(max):
n,a,b = 0,0,1
while n < max:
yield b #保存了函数的中断状态,并返回值
a,b = b,a+b
n = n+1
return "down"
f = fib(9) #生成器函数
list1 = (i*2 for i in range(10)) #生成器列表
print(isinstance(list,Iterable))
print(isinstance(tuple,Iterable))
print(isinstance(dict,Iterable))
print(isinstance(str,Iterable))
print(isinstance(f,Iterable))
print(isinstance(list1,Iterable))
结果可知 都为True
2.判断是否为迭代器
迭代器:
可以被_next_()函数调用并且可以返回一个值的对象 --> 迭代器
这里也需要导入Iterator模块
from collections.abc import Iterator # 导入判断是否为迭代器的方法
list = [] #列表
tuple = () #元组
str = '' #字符串
dict = {} #字典
def fib(max):
n,a,b = 0,0,1
while n < max:
yield b #保存了函数的中断状态,并返回值
a,b = b,a+b
n = n+1
return "down"
f = fib(9) #生成器函数
list1 = (i*2 for i in range(10)) #生成器列表
print(isinstance(list,Iterator))
print(isinstance(dict,Iterator))
print(isinstance(list1,Iterator))
print(isinstance(f,Iterator))
结果为 前两个为False
后面两个可以被_next_()方法接受 所以为True
3.将可迭代对象转化为迭代器
用iter方法
list = ['apache', 'nginx', 'tomcat']
tuple = ()
str = ''
dict = {'yunwei':1,'linux':2}
list_i = iter(list)
dict_i = iter(dict)
print(isinstance(list_i,Iterator))
print(isinstance(dict_i,Iterator))
print(dict_i.__next__())
print(dict_i.__next__())
结果就为True 就可以用_next()方法取元素了
总结
1)凡是可作用于for循环的对象都是Iterable(可迭代对象)类型;
2) 凡是可作用域next()函数的对象的都是迭代器类型,它们表示一个惰性计算的序列
3) 集合数据类型如list、dict、str等是Iterable但不是Iterabtor
不过可以通过iter()函数获得一个迭代器对象