生成器(generator)
一般的函数return后,函数栈被销毁,下次调用的时候从新开始。生成器函数可以yield一个值,暂停执行,把执行权交给调用函数,当我们获取另一个值得时候,生成器函数可以恢复执行。
调用生成器函数的时候,我们得到的是一个生成器对象(类似迭代器)。当我们在生成器对象上调用next()便会得到yield返回的值。下面是两个例子,一个是通过next()获取yield值,另一个是通过循环。
- next()
code sample:
def generator_sample():
yield "Hello"
yield "World"
generator_obj = generator_sample()
print(generator_obj)
print(next(generator_obj))
print(next(generator_obj))
result:
<generator object generator_sample at 0x00D910B0>
Hello
World
- loop
code sample:
def generator_sample():
yield "Hello"
yield "World"
generator_obj = generator_sample()
print(generator_obj)
for i in generator_obj:
print(i)
result:
<generator object generator_sample at 0x005A10B0>
Hello
World
生成器函数的用处:通过迭代而不是一次性获取所有值,避免消耗大内存。可以利用生成器函数返回多个值。
基于生成器的协程
通过生成器,我们可以从函数中获取值。那么如何给生成器函数发送值呢?这就是协程的作用。我们可以通过generator对象的send()函数给生成器函数返回一个值。如下示例:
def coroutine_base_on_generator():
temp = yield "yes"
yield temp
c_obj = coroutine_base_on_generator()
print(next(c_obj))
print(c_obj.send("you are right"))
result:
yes
you are right
asyncio module
从python3.4,引入了asyncio模块,提供了优雅的异步编程接口。但是依然是基于生成器的协程。下面是asyncio module的示例:
import asyncio
import datetime
import random
@asyncio.coroutine
def asyncio_module_sample(num, count):
i = 0
while i < count:
print("Loop: {} Time: {}".format(num, i))
yield from asyncio.sleep(random.randint(0, 5))
i += 1
loop = asyncio.get_event_loop()
task1 = loop.create_task(asyncio_module_sample(1, 5))
task2 = loop.create_task(asyncio_module_sample(2, 5))
try:
loop.run_until_complete(asyncio.wait([task1, task2]))
finally:
loop.close()
result:
Loop: 1 Time: 0
Loop: 2 Time: 0
Loop: 2 Time: 1
Loop: 1 Time: 1
Loop: 2 Time: 2
Loop: 1 Time: 2
Loop: 2 Time: 3
Loop: 2 Time: 4
Loop: 1 Time: 3
Loop: 1 Time: 4
async/await
从python3.5,引入了async/await语法关键字。所以之前的例子可以用async/await方式重写:
import asyncio
import datetime
import random
async def async_await_sample(num, count):
i = 0
while i < count:
print("Loop: {} Time: {}".format(num, i))
await asyncio.sleep(random.randint(0, 5))
i += 1
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(asyncio.gather(async_await_sample(1, 5), async_await_sample(2, 5)))
finally:
loop.close()
result:
Loop: 1 Time: 0
Loop: 2 Time: 0
Loop: 1 Time: 1
Loop: 2 Time: 1
Loop: 1 Time: 2
Loop: 1 Time: 3
Loop: 2 Time: 2
Loop: 1 Time: 4
Loop: 2 Time: 3
Loop: 2 Time: 4
async/await方式和asyncio module方式在功能上并没有区别,只是语法的差异。但是两者不能混用。
网友评论