【python + flask】上下文管理器的妙用,帮你写出更加抽象的框架代码,有效减少代码量

15 篇文章 0 订阅

1. 利用上下问管理器处理数据库写入操作

			user = User()
            user.email = form.email.data
            user.nickname = form.nickname.data
            user.password = form.password.data
            try:
                db.session.add(user)
                db.session.commit()
                return redirect(url_for('web.index'))
            except Exception as e:
                # 这种写法目前是有问题的,需要加入回滚,否则一旦提交失败,会造成阻塞到其它提交 !! rollback
                db.session.rollback()
                print("出错了:!" + traceback.format_exc())
                raise e

上面是操作用户表的一个例子,用try except 将可能出mysql错误的代码包裹住。
但是我们在一个项目中,有至少几十张表,需要处理读写错误的地方很多,那么,每个地方都用try except 包裹住么,这样太麻烦了。
因此,需要利用上下文管理器,只需要在业务侧保留1-2行代码

db.session.add(user)

而开启事务和回滚操作都交给框架完成是最优解。
这时候就需要用到了,上下文管理器。

2.什么是上下文管理器

class MyResource():
    def __enter__(self):
        print("i am enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("i am exit")

        if exc_type:
            print(exc_type, exc_val, exc_tb)
            print(traceback.format_exc())
            raise exc_val

    def query(self, data):
        print("i am query data")


with MyResource() as r:
    r.query(data=[])
i am enter
i am query data
i am exit

在enter中处理开启try
在exit中处理except的部分

注意这个mysource中的enter函数,return了self本身。

3. 用contextmanager简化

from contextlib import contextmanager


def make_myresource():
    print("connect to resource!")
    return MyResource()
    print("close resource connection!")


try:
    with make_myresource() as r:
        try:
            r.query([])
        except Exception as e:
            print(traceback.format_exc())
except Exception as e:
    print(e)

报错,我承认,我是故意让他出错的,需要将return 改成yield,yield 很熟悉的

connect to resource!
'MyResource' object is not an iterato

输出正常了:

connect to resource!
i am query data
close resource connection!

with 语句 会将yield后面的表达式返回r,也就是执行到yield后面,等query执行完成后,再去返回yield的位置继续向下执行。
return的意思是返回,返回了就不能再回到原来的位置继续执行了,yield是让渡,让渡出去,等完成了,还能再回来
yield 是生成器,自行学习一下。

4.一个小应用

from contextlib import contextmanager
@contextmanager
def book_mark():
	print("《",end="")
	yield
	print(">>",end="")
with book_mark():
	print("且将生活一饮而尽")

输出了:《且将生活一饮而尽》
案例4就和我们的要求极为相近了,yield 不需要返回什么,
with 也不需要as搭配。

做一下类比:
try == 《
except == 》
yield 也不需要返回

def auto_commit(db):
	try:
		yield
		db.session.commit()
	except Exception as e:
		db.session.rollback()
		raise e
		

或者也可以用对象的方式:

class C:
    @contextmanager
    def ccc(self):
        print("1111")
        yield
        print("33333")


c = C()
with c.ccc():
    print("2222")

输出:

1111
2222
33333

5.终极修改方案

class SQLAlchemy(_SQLAlchemy):
    @contextmanager
    def auto_commit(self):
        try:
            yield
            self.session.commit()
        except Exception as e:
            self.session.rollback()
            raise e


db = SQLAlchemy()

重写sqlalchemy

		with db.auto_commit():
			user = User()
            user.email = form.email.data
            user.nickname = form.nickname.data
            user.password = form.password.data
            db.session.add(user)
         return redirect(url_for('web.index'))

6.拓展

上下文管理器其实是一种面向切面的编程方式,比如数据库操作,进入函数和出去函数的时候记录日志【尤其是微服务之前相互调用】,可以在最底层的http请求的函数加上下午管理器,自动的将入参和返回值记录下来。返回值有的需要记录全量,有的则需要记录状态码【全量数据太多的话】,自行处理吧。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值