??本文主要講兩個(gè)方面的東西,一個(gè)是迭代方面,對(duì)應(yīng)是生成器,語(yǔ)法是yield。另一個(gè)方面是異步編程,對(duì)應(yīng)是協(xié)程,語(yǔ)法是async。
yield
??首先生成器是用來(lái)迭代的。所以要先弄清可迭代的,容器,迭代器,生成器的關(guān)系。
??簡(jiǎn)單來(lái)說(shuō),可以for i in x這樣用的x就是可迭代的。它包括容器和迭代器。
容器
??容器就像列表,可以放數(shù)據(jù),為什么可以放for里面迭代呢,方便吧。
迭代器
??迭代器就是實(shí)現(xiàn)__iter__()和__next__()的,__iter__返回自己,__next__返回迭代的下一個(gè)值。在for里其實(shí)是隱式調(diào)用了__next__()。
class Iterator:
def __init__(self):
self.data = 0
def __iter__(self):
return self
def __next__(self):
self.data += 1
if self.data > 5:
raise StopIteration
return self.data
if __name__ == '__main__':
I = Iterator()
try:
for i in I:
print(i)
except StopIteration:
pass
??迭代器迭代完了后繼續(xù)調(diào)用__next__()結(jié)合觸發(fā)StopIteration錯(cuò)誤。
生成器
??生成器就是一種特殊的迭代器。它外表像函數(shù),但是用yield代替return。調(diào)用生成器會(huì)返回一個(gè)對(duì)象,顯式或隱式(for里面)調(diào)用next就會(huì)執(zhí)行到y(tǒng)ield返回一個(gè)值,然后暫停,下次從這個(gè)地方繼續(xù)。一個(gè)例子如下:
def f(max):
n = 0
while n < max:
yield n
n += 1
if __name__ == '__main__':
for i in f(5):
print(i)
??然后人們就想要是加入send(),可以給生成器發(fā)送信息,不就實(shí)現(xiàn)了協(xié)程么。所以就有了send()函數(shù)。用a = yield *,執(zhí)行到y(tǒng)ield暫停后,下次執(zhí)行,就把send的值賦值給a。
def f(max):
n = 0
while n < max:
a = yield n
n = n + a + 1
if __name__ == '__main__':
fun = f(5)
print(fun.send(None))
try:
while True:
print(fun.send(1))
except StopIteration:
pass
??這個(gè)代碼輸出的是0,2,4。當(dāng)然,還有yield from等配合使用。這里就不講了。
async/await
??這個(gè)語(yǔ)法是專門為協(xié)程設(shè)計(jì)的,為了使python更簡(jiǎn)潔好用。async def申明一個(gè)協(xié)程函數(shù),函數(shù)里可以使用await等待其他協(xié)程函數(shù)執(zhí)行完再繼續(xù)執(zhí)行自己的代碼。
async def async_f():
return 1
async def await_f():
result = await async_f()
return result + 1
if __name__ == '__main__':
try:
await_f().send(None)
except StopIteration as e:
print(e.value)
??輸出2。但是這樣好像沒(méi)什么意義。其實(shí)這兩條語(yǔ)法一般是結(jié)合asyncio標(biāo)準(zhǔn)庫(kù)來(lái)用的。
import asyncio
async def hello():
print('Send request')
await asyncio.sleep(1)
print('Get')
async def cal():
n = 0
for i in range(5):
n += i
print(n)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
tasks = [hello(), cal()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
輸出:
Send request
10(停頓1秒左右)
Get
異步編程適合IO操作,在等待的時(shí)候可以先進(jìn)行其他操作,提高cpu利用率。asyncio正是這么一個(gè)幫忙自動(dòng)切換協(xié)程的庫(kù)。
異步生成器
??這個(gè)名詞不知道準(zhǔn)不準(zhǔn)確,反正就是async和yield結(jié)合用法吧。這是一個(gè)買西紅柿和馬鈴薯的例子。從貨架上一個(gè)一個(gè)拿,沒(méi)有了就叫售貨員加。
import asyncio
all_potatos = [1, 1, 1, 1, 1]
all_tomatos = [1, 1, 1, 1, 1]
async def ask_for_potato():
all_potatos.append(1)
async def ask_for_tomato():
all_potatos.append(1)
async def take_potatos(num):
count = 0
while True:
if len(all_potatos) == 0:
await ask_for_potato()
potato = all_potatos.pop()
yield potato
count += 1
if count == num:
break
async def take_tomatos(num):
count = 0
while True:
if len(all_tomatos) == 0:
await ask_for_tomato()
tomato = all_tomatos.pop()
yield tomato
count += 1
if count == num:
break
async def buy_potatos():
bucket = []
async for i in take_potatos(50):
bucket.append(i)
print(len(bucket))
async def buy_tomatos():
bucket = []
async for i in take_potatos(50):
bucket.append(i)
print(len(bucket))
if __name__ == '__main__':
loop = asyncio.get_event_loop()
tasks = [buy_potatos(), buy_tomatos()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()