Python中的try finally块是一个异常捕获的手段,同时Python中还有一个功能就是try finally块里的finally语句块总是会被执行的,并且会使用try语句块里的变量。如下示例代码及其运行结果:本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
#示例1 def test(): try: print("a") yield 1 return 2 finally: print("bbbb") return 0 a = test() print(a) print("-"*30) print(next(a)) print(a) print("="*30) print(next(a)) #示例2 def test2(): try: print("a") return 2 finally: print("b") #return 0 a = test2() print('-'*30) print(a)本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
执行结果如图:本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
示例1中测试了yield的执行原理,在初次调用test的时候并不会进行print打印,而是返回了一个生成器<generator object test at 0x0000000001DA5EB0>。在执行next操作后才开始输出a和1。之后如果再调用next方法就会报下面的错。因为yield已经处理完了,后面不能再进行迭代(可以看后面使用while循环来演示这块)本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
Traceback (most recent call last): File "test/try.py", line 18, in <module> print(next(a)) StopIteration: 0本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
示例2中更清晰地呈现了try finally的执行逻辑。先输出a再输出b,然后finally中的return如果存在就会覆盖try中的return。特别要注意的是test中的finally print在执行完test2中的finally后也执行了。所以Python中try finally块里的finally语句块总是会被执行的。本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
使用循环来演示yield的作用,对yield的功能就一目了然了。本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
def demo(): print("start") while 1: yield 'yield_value' print("return yield") fun = demo() print(fun) print(next(fun)) print("-"*30) print(next(fun)) print(next(fun)) print(next(fun)) print(next(fun)) print("!"*30)本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
#上述程序执行时输出:本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
W:\green_soft\python-3.8.6rc1-embed-amd64>python test/try.py <generator object demo at 0x0000000001DB5E40> start yield_value ------------------------------ return yield yield_value return yield yield_value return yield yield_value return yield yield_value !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
事情还没有结束,从上面是得出一个结论,finally一定会被执行,也正因于此,有些程序框架就会利用它的这一点拿来当做数据库的处理,让finally去操作数据库的关闭等从而实现在程序的最后执行时刻关闭数据库连接。如fastapi框架中的:https://fastapi.tiangolo.com/tutorial/sql-databases/ 中的示例程序:本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
# Dependency def get_db(): db = SessionLocal() try: yield db finally: db.close()本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
程序中通过Dependency拿到数据库连接,在程序最后执行时间里关闭数据库。但在实际应用中我发现并不是这样,我使用的uvicorn作本地的后端服务,finally中的程序确实会执行,但每次打印finally的日志都是在下一个请求里去打印,即数据库连接并不是在当前请求执行完毕时关闭掉的,而是在下一次请求开始时关闭。这就会造成在单个进程中如果存在进程执行程序重合。就有可能后进行的请求但先关闭的情况下导致先进行的请求的数据库连接丢失(被关闭)。这是我目前基于公司的业务排查到的问题,经过我测试,我使用return db能解决这个问题,也不会造成数据库连接的浪费占满等情况。本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
todo:我们出现这样的问题也可能是我们使用的数据库操作模块和fastapi官网示例的不同有关,我们使用的是pymysql连接类,而官网使用的是SessionLocal。我没有再去验证,欢迎大家有追加尝试并无法反馈。本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
from .database import SessionLocal, engine # Dependency def get_db(): db = SessionLocal() try: yield db finally: db.close()本文地址:http://www.04007.cn/article/1017.html,未经许可,不得转载.
本文地址:http://www.04007.cn/article/1017.html 未经许可,不得转载. 手机访问本页请扫描右下方二维码.
![]() |
![]() |
手机扫码直接打开本页面 |