新聞中心
[[413590]]

成都創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)提供從項(xiàng)目策劃、軟件開(kāi)發(fā),軟件安全維護(hù)、網(wǎng)站優(yōu)化(SEO)、網(wǎng)站分析、效果評(píng)估等整套的建站服務(wù),主營(yíng)業(yè)務(wù)為網(wǎng)站設(shè)計(jì)、網(wǎng)站制作,成都App定制開(kāi)發(fā)以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。成都創(chuàng)新互聯(lián)公司深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
熟悉 Golang 的同學(xué)都知道,Golang 里面有一個(gè)關(guān)鍵詞叫做defer,它可以實(shí)現(xiàn)延遲調(diào)用。
實(shí)際上在 Python 里面也有相關(guān)的語(yǔ)法,那就是contextlib.ExitStack。
我們來(lái)看這樣一個(gè)場(chǎng)景:
我有一個(gè)函數(shù)parse,它的作用是從 Redis 中持續(xù)讀入數(shù)據(jù),并寫(xiě)入到MongoDB 中。示例代碼如下:
- import json
- import redis
- import pymongo
- client = redis.Redis()
- handler = pymongo.MongoClient().test.data
- def parse():
- data = client.lpop('test')
- if not data:
- return
- handler.insert_one(json.loads(data))
但現(xiàn)在我想增加一個(gè)需求,當(dāng)Redis 讀取結(jié)束或者讀取數(shù)據(jù)報(bào)錯(cuò)的時(shí)候,能把當(dāng)前的時(shí)間也寫(xiě)入到MongoDB 中。
那么代碼可能變成下面這樣:
- import json
- import redis
- import datetime
- import pymongo
- client = redis.Redis()
- handler = pymongo.MongoClient().test.data
- def parse():
- while True:
- try:
- data = client.lpop('test')
- if not data:
- handler.insert_one({'finished': True, 'ts': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
- return
- handler.insert_one(json.loads(data))
- except Exception:
- handler.insert_one({'finished': True, 'ts': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'})
可以看到,代碼變得很難看了。
現(xiàn)在,我們可以使用延遲調(diào)用來(lái)讓代碼變得更好看。
要實(shí)現(xiàn)這個(gè)目的,就可以開(kāi)始使用ExitStack了。它可以注冊(cè)多個(gè)回調(diào)函數(shù),在退出上下文縮進(jìn)時(shí)執(zhí)行。
我們先來(lái)看一個(gè)簡(jiǎn)單的例子:
- import contextlib
- def callback_1():
- print('我是第一個(gè)回調(diào)函數(shù)')
- def callback_2(x):
- print(f'我是第二個(gè)回調(diào)函數(shù),傳入?yún)?shù):{x}')
- with contextlib.ExitStack() as stack:
- stack.callback(callback_1)
- stack.callback(callback_2, 100)
- print(12345)
- print('xxxx')
- print('退出縮進(jìn)')
運(yùn)行效果如下圖所示:
可以看出以下特點(diǎn):
- 被添加的回調(diào)函數(shù)進(jìn)入了一個(gè)棧,所以后添加的回調(diào)函數(shù)先調(diào)用
- 回調(diào)函數(shù)會(huì)在結(jié)束縮進(jìn)的時(shí)候被調(diào)用
現(xiàn)在我們來(lái)人工構(gòu)造一個(gè)異常:
可以看到,即使縮進(jìn)里面出現(xiàn)了報(bào)錯(cuò),回調(diào)函數(shù)仍然可以正常運(yùn)行。等所有回調(diào)函數(shù)運(yùn)行完成以后,Python 才會(huì)退出。
基于以上特點(diǎn),我們就可以來(lái)重構(gòu)最開(kāi)始的代碼了:
- import json
- import redis
- import datetime
- import pymongo
- import contextlib
- client = redis.Redis()
- handler = pymongo.MongoClient().test.data
- def add_ts():
- handler.insert_one({'finished': True, 'ts': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
- def parse():
- with contextlib.ExitStack() as stack:
- stack.callback(add_ts)
- while True:
- data = client.lpop('test')
- if not data:
- return
- handler.insert_one(json.loads(data))
無(wú)論是正常運(yùn)行結(jié)束還是運(yùn)行過(guò)程中報(bào)錯(cuò),add_ts函數(shù)都會(huì)正常運(yùn)行,確保始終增加一條日期數(shù)據(jù)。
本文轉(zhuǎn)載自微信公眾號(hào)「未聞Code」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系未聞Code公眾號(hào)。
網(wǎng)頁(yè)標(biāo)題:一日一技:在Python中實(shí)現(xiàn)延遲調(diào)用
鏈接分享:http://www.5511xx.com/article/coeshcc.html


咨詢
建站咨詢
