python使用@contextmanager来定义上下文管理器(一篇文章,彻底明白!码文并茂,简单明了)

版权声明: https://blog.csdn.net/JENREY/article/details/86690018

首先引出为什么要使用上下文管理器:我们的代码图如下

通过上图代码我们可以发现,我们每次都要进行db.session.commit()我们可能在项目的很多地方都会使用到,如果我们每次都要写try except 然后在里面回滚,这些重复的代码我们尽可能的要去避免。下面我们就来解决这个问题。

我们先来回顾一下上下文管理器-with

如果我们要定义上下文管理器,就需要在这类里面定义__enter____exit__这两个方法。

有没有什么简化的方法不需要我们直接定义__enter__和__exit__呢?

python提供了一个装饰器叫@contextmanager,是位于contextlib模块下的。

借助contextmanager装饰器,我们可以简化MyResource的定义

现在我们不要__enter__和__exit__方法,只保留核心方法query(),注意我们只是不想在定义__enter__和__exit__这两个方法,但是他们里面所执行的语句我们还是需要实现的。在进入上下文管理器的时候打印__enter__里面的方法,在退出的时候打印__exit__里面的方法。

扫描二维码关注公众号,回复: 5126072 查看本文章

所以最终的代码如上图所示。

大家都说利用@contextmanager这个内置的装饰器可以减化上下文管理器的定义,但是我不这样认为。但是这样写有一个非常的好处,就是使用@contextmanager的好处就是给了我们一个机会,让我们把原来不是上下文管理器的类变成了上下文管理器,假如这个MyResource的类不是我们自己编写的,比如说是flask提供给我们的或者是第三方类库提供给我们的,我们去改变源码在里面加__enter__和__exit__方法是不合适的,但是我们却可以在MyResource的类的外部使用@contextmanager把MyResource包装成一个上下文管理器。

例如:

注意下图第三方的SQLAlchemy的名字被我们as成了_SQLAlchemy,这样SQLAlchemy就是父类的子类的。

我们如何为一个第三方的类库新增加一个方法呢?我们可以新建一个子类,然后继承SQLAlchemy

这样我们就可以把代码变成下面这样了

对比之前的是不是简单了呢?(下图为未使用上下文管理器之前的代码),上图仅仅一个with就解决了try except的繁琐。


扩展知识点:

现在我们想打印一本书的名字,但是每一次前后都要自己加书名号太烦了,书名是我们从数据库中查出来的,但是我们在数据库中保存是不会加书名号的,现在我们取出来显示的时候想加书名号,那么我们使用@contextmanager解决

因为我们的with后面没有as,所以我们不需要yield返回任何的结果,这里只写一个yield是可以的。 

但是因为有换行,那么我们就在后面加上end=''就行啦

这里的用法就是@contextmanager的另一种用法,和上下文管理器是没有关系的。


猜你喜欢

转载自blog.csdn.net/JENREY/article/details/86690018