from collections import Iterable
# 模拟取款
def cash_atm(totalmoney):
while totalmoney>0:
print("=======(可取金额:%s )=======" % totalmoney)
totalmoney -= 100
yield 100
print("=======( 余额:%s )=======" % totalmoney)
atm = cash_atm(1000)
# 查看atm是个啥,是一个generator
print(type(atm))
# 判断atm是否可迭代
print(isinstance(atm, Iterable))
# 获取100现金
print(atm.__next__())
# 消费金额
print("买了本书把钱花完了...")
# 我想去买个礼物给女朋友,可没有钱了再去取钱
print(atm.__next__())
'''
定义:如果一个函数返回的是一个迭代器,那么这个函数就是生成器
那么如果一个函数要返回一个迭代器则需要使用yield语法,
该函数就可以返回一个迭代器
'''
分析:上面的cash_atm是一个生成器,它调用时返回一个迭代器,根据迭代器的特性,我们只能往下走,不能往回退,上面比较特殊的地方就是:每次请求执行atm的next时,都能够从上一次后面继续往下走,而这个关键在于yield语法,yield是能够跳出当前函数,并且保存执行的状态,下一次调用next时,可以从保存状态继续往下走。
应用分析:
这个生成器有什么应用场景呢?比如说:如果一个操作需要花费很长时间,如果是串行执行的,那么就必须等待操作执行完才可以去干其他的事情,那么这段时间内,你就处于被阻塞状态的,这是不理想的状态。最好的状态是什么呢?比如说我调用接口a,这个接口需要花费一段时间。最好的效果呢就是,我调用该接口,然后去做其他的事,一旦这个接口处理完成后通知我,我来处理这个结果返回的后续操作。这个就是异步操作,相当于我开一个线程去处理接口,接口处理完后会通知主线程处理。
场景应用:
模拟异步场景: 有一个餐馆,有一个厨师,有2名食客,食客点包子,厨师做包子,厨师做完后,食客开始吃。
这是一个生产消费模型,实现一个单线程的异步效果?
实现代码如下:
import time
# 生产者消费者模型:厨师生产者,食客消费者
# 消费者
def consumer(name):
print("服务员给我[%s]上包子..."%name)
while True:
bz = yield
print("%s,你好!包子[%s]来了!"%(name,bz))
# 生产者
def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("厨师[%s]开始做包子了..."%name)
for i in range(10):
time.sleep(1)
print("我[%s]做好两个包子!"%name)
c.send(i)
c2.send(i)
producer('ckmike')
总结:
上面的代码是一个简单的单线程异步效果。生成器的作用非常大。消费者不需要等生产者把所有都准备好就可以把现有的消息消费掉,消费者只是接受消息信息号,把当前的信息处理掉,而生产者负责生成消息,并且信号发送给消费者。上面的效果可能我们还是有点模糊生成器有啥用。比如说现在我要获取一个斐波那契数列。我们没有必要把所有的值一次性加载到内存中,我们可以要一个拿一个(通过生成式实现),概念:这种一边循环一边计算的机制,称为生成器:generator。,与Linux下的cat命令类似,你不需要把大文件一次性加载到内存中,你只要获取部分到内存中,这样大大节省了内存。
菲波那切数列实现:
# 菲波那切数列
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
f=fib(10)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())