# 9.2 contextmanager

## 1.contextmanager简单讲解

contextmanager可以简化上下文管理器，不需要我们编写\_\_enter\_\_和\_\_exit\_\_函数。他给了我们一个机会，让我们把之前一个不是上下文管理器的类变成一个上下文管理器，而不需要我们去修改这个类的源代码

其中的yield的作用，是中断当前函数执行流程，先去执行yield出去的部分的代码执行流程

下面的代码的作用，在书籍前后自动加上《》

```python
@contextmanager
def book_mark():
    print('《', end='')
    yield
    print('》', end='')


with book_mark():
    print('钢铁',end='')
```

## 2.结合继承，contextmanager，yield，rollback来简化try-except的数据库事务代码

1.我们可以通过contextmanager实现一个上下文管理器，将try-except的代码放在contextmanager里，将具体的业务逻辑代码yield出去 2.SQLAlchemy并没有这个上下文管理器，但是我们可以做一个子类，来扩展他的功能 3.编写子类的时候，命名是非常不好起的，我们可以改变父类的名字，给子类命名为原父类的名字

models/base.py

```python
from flask_sqlalchemy import SQLAlchemy as _SQLAlcmemy

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

使用auto\_commit的save\_to\_gifts视图函数

```python
@web.route('/gifts/book/<isbn>')
@login_required
def save_to_gifts(isbn):
    if current_user.can_save_to_list(isbn):
        with db.auto_commit():
            gift = Gift()
            gift.isbn = isbn
            gift.uid = current_user.id

            current_user.beans += current_app.config['BEANS_UPLOAD_ONE_BOOK']

            db.session.add(gift)
            db.session.add(current_user)
    else:
        flash("这本书以添加进您的赠送清单或已经存在于您的心愿清单，请不要重复添加")
    return "aaa"
```

使用auto\_commit的register视图函数

```python
@web.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm(request.form)
    if request.method == 'POST' and form.validate():
        with db.auto_commit():
            user = User()
            user.set_attrs(form.data)

            db.session.add(user)

        return redirect(url_for('web.login'))

    return render_template('auth/register.html', form=form)
```

干货：

> 1.遇到比较复杂的问题，应该把他单独的分离出来，在一个单独的文件里来编写一些非常简单的源码，因为业务越简单，越能够让我们去关注知识和原理本身的相关问题。 2.高级编程不是在于学习更高级的语法（学会更好），更关键的在于能够用自己所学的知识，写出更好的代码来 3.对知识的综合运用能力很重要，将单个的知识点组合在一起写出一段很好的代码来


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://flask-yushu.gitbook.io/yushu/9.-shu-ji-jiao-yi-mo-xing/9.1-contextmanager.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
