关于一个yield和with的问题

from flask_sqlalchemy import SQLAlchemy as BaseSQLAlchemy
from contextlib import contextmanager
 
#自定义一个SQLAlchemy继承flask_sqlalchemy的,方便自定义方法!!!
class  SQLAlchemy(BaseSQLAlchemy):
 
    #利用contextmanager管理器,对try/except语句封装,使用的时候必须和with结合!!!
    @contextmanager
    def auto_commit_db(self):
        try:
            yield  # <---这里这个yield怎么理解?
            self.session.commit()
        except Exception as e:
           # 加入数据库commit提交失败,必须回滚!!!
           self.session.rollback()
           raise e
 
db = SQLAlchemy()

添加数据的时候需要用到with:

with db.auto_commit_db():
    user_db = User(nickname=self.nickname, password=self.password)
    db.session.add(user_db)
阅读 2.4k
2 个回答

建议深入理解生成器后研究下contextlib的代码,下面简单解释下contextmanager怎么把被修饰对象的 try ... finally ... 分配到with约定的 __enter__, __exit__方法中的。

contextmanager的使用方式,可见他要求装饰对象是一个生成器

    Typical usage:

        @contextmanager
        def some_generator(<arguments>):
            <setup>
            try:
                yield <value>
            finally:
                <cleanup>

此处yield的作用就是协程切换,如果yield后有值,还可以传出(with 子句 as 后)。
contextmanager 在 __enter__ 中第一次调用 next(gen),代码执行到auto_commit_dbyield处转出,执行 with 子句的代码

user_db = User(nickname=self.nickname, password=self.password)
db.session.add(user_db)

contextmanager 在 __exit__ 中第二次调用 next(gen),也就就是with子句结束前执行auto_commit_db的其余部分,完成资源管理的其他任务。

等待 self.session.commit()执行返回

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题