熟悉Golang的同学都知道,Golang中有一个关键字叫做defer,可以实现延迟调用。其实Python中也有一个相关的语法,就是contextlib.ExitStack。我们来看这样一个场景:我有一个函数parse,用来不断的从Redis读取数据,写入MongoDB。示例代码如下:importjsonimportredisimportpymongoclient=redis.Redis()handler=pymongo.MongoClient().test.datadefparse():data=client.lpop('test')ifnotdata:returnhandler.insert_one(json.loads(data))但是现在我想增加一个需求,当Redis读到结束或者读到数据报错的时候,也可以把当前时间写入MongoDB。那么代码可能会变成如下:'完成':真,'ts':datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S')})returnhandler.insert_one(json.loads(data))exceptException:handler.insert_one({'finished':True,'ts':datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S'})可以看吧,代码变丑了先看一个简单的例子:importcontextlibdefcallback_1():print('我是第一个回调函数')defcallback_2(x):print(f'我是第二个回调函数,传入参数:{x}')withcontextlib.ExitStack()asstack:stack.callback(callback_1)stack.callback(callback_2,100)print(12345)print('xxxx')print('exitindentation')运行效果如下图:可以看出有如下特点:添加的回调函数入栈,所以后面添加的回调函数先调用回调函数,缩进结束时调用。现在我们手动构造一个异常:可以看到,即使有一个If报错,回调函数依然可以正常运行。直到所有回调函数运行完毕,Python才会退出。基于以上特点,我们可以重构初始代码:.datetime.now().strftime('%Y-%m-%d%H:%M:%S')})defparse():withcontextlib.ExitStack()assack:stack.callback(add_ts)whileTrue:data=client.lpop('test')ifnotdata:returnhandler.insert_one(json.loads(data))无论正常运行结束还是运行中报错,add_ts函数都会正常运行,确保一段date总是添加数据。本文转载自微信公众号“闻所未闻的密码”,可通过以下二维码关注。转载本文请联系Code公众号。
