前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python with上下文管理及自定义上下文管理

Python with上下文管理及自定义上下文管理

作者头像
Python碎片公众号
发布2021-02-26 14:29:53
8360
发布2021-02-26 14:29:53
举报
文章被收录于专栏:Python碎片公众号的专栏

一、上下文管理器

上下文管理器是对Context Manager的翻译 ,上下文是 context 直译的叫法,在程序中用来表示代码执行过程中所处的前后环境.

在文件操作时,需要打开、关闭文件,而在文件在进行读写操作时,就是处在文件操作的上下文中,也就是文件操作环境中.

语法: with

with 语句是 Pyhton 提供的一种简化语法,从Python 2.5 开始引入的一种与异常处理相关的功能,适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“扫尾”操作,释放资源.

比如文件使用后自动关闭、数据库连接的自动关闭等.

二、with上下文管理器示例

代码语言:javascript
复制
with open('test.txt', 'a') as f:
    f.write('上下文管理\n')

运行以上代码,会在代码同级目录下创建一个叫test.txt的文本文件,并在文件中追加内容"上下文管理",并换行.

在执行 with 语句时,首先执行 with 后面的 open 代码(如果已经有test.txt文件则打开,如果没有test.txt文件则创建),然后通过as将代码的结果保存到 f 中(相当于给test.txt起个别名f,f只是一个变量名,您可以自定义)

在with下面的代码块是对test.txt执行的操作,如示例中的操作是写入内容.

在操作后,不需要对文件test.txt进行关闭操作f.close(),with上下文管理器会在文件使用完后帮我们关闭test.txt文件.

这么做即可以简化代码,又可以避免因粗心忘记执行关闭操作而出现异常,因为在实际开发中,打开一个文件后,进行的操作可能非常复杂,这种情况是很可能忘记做"扫尾"操作的.

三、with上下文管理的原理

在使用with上下文管理器时,并不是不需要关闭文件,而是文件的关闭操作在 with 的上下文管理器中已经实现了.当文件操作执行完成后,with语句会自动调用上下文管理器里的关闭语句来关闭文件资源.

但是,我们的应用场景并不是一成必变,with是怎么实现帮我们做"扫尾"操作的呢?

with语句在执行时,调用上下文管理器中的 __enter__ 和 __exit__ 两个方法,这两个方法就是上下文管理器中实现的方法.

__enter__ 方法会在执行with后面的语句时执行,一般用来处理操作前的内容.比如打开文件,创建对象,初始化等.

__exit__ 方法会在with内的代码执行完毕后执行,一般用来处理一些善后收尾工作,比如文件的关闭,数据库的关闭等.

四、自定义上下文管理器

根据上下文管理的原理,上下文管理器的原理是实现了__enter__和__exit__这两个方法,所以我们可以根据此原理来自定义自己的上下文管理器.

在自定义上下文管理器时,只要在类中实现 __enter__ 和 __exit__ 两个方法即可.

代码语言:javascript
复制
class OpenFile(object):
    """自定义上下文管理类"""
 
    def __init__(self, file, mode):
        self._file = file
        self._mode = mode
 
    def __enter__(self):
        print('__enter__  打开文件')
        self._handle = open(self._file, self._mode)
        return self._handle
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__ 关闭文件')
        self._handle.close()
 
 
with OpenFile('test01.txt', 'w') as f:
    f.write('自定义上下文管理\n')

上面的代码中,我们不是使用Python实现好的open来打开文件,而是通过自定义的OpenFile类来完成文件的操作.

代码运行过程和结果与用open类似,会先执行OpenFile后的代码(自定义类OpenFile中的代码),如果存在文件test01.txt,打开文件并在其中写入"自定义上下文管理",如果不存在文件test01.txt,则创建文件并写入"自定义上下文管理".

说明我们成功实现了自定义上下文管理.

五、上下文管理中的自定义异常处理

我们看到,__exit__ 方法中有三个参数exc_type ,exc_val 和exc_tb ,这三个参数是用来接收异常信息的,如果代码在运行时发生异常,异常信息会被保存到这三个参数中.

代码语言:javascript
复制
class OpenFile(object):
    """自定义上下文管理类"""
 
    def __init__(self, file, mode):
        self._file = file
        self._mode = mode
 
    def __enter__(self):
        self._handle = open(self._file, self._mode)
        return self._handle
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('Type: ', exc_type)
        print('Value:', exc_val)
        print('TreacBack:', exc_tb)
        self._handle.close()
 
 
with OpenFile('test01.txt', 'r') as f:
    f.write('自定义上下文管理\n')

上面的代码中,传入的'w'换成了'r',会出现异常,因为以读的模式打开文件,不能进行写操作.运行结果为:

代码语言:javascript
复制
Traceback (most recent call last):
Type:  <class 'io.UnsupportedOperation'>
  File "python_demo/with_demo.py", line 45, in <module>
Value: not writable
    f.write('自定义上下文管理\n')
TreacBack: <traceback object at 0x0000024EA5E11508>
io.UnsupportedOperation: not writable

可以看到我们打印的三个参数exc_type ,exc_val 和exc_tb的值.分别存储了异常的以下信息:

exc_type : 异常类型

exc_val : 异常值

exc_tb : 异常回溯追踪

当with中执行的语句发生异常时,异常信息会被发送到 __exit__ 方法的参数中,这时可以根据情况选择如何处理异常.

因为在 __exit__函数执行异常处理时,会根据函数的返回值决定是否将系统抛出的异常继续向外抛出.如果返回值为 False 就会向外抛出,用户就会看到.如果返回值为 True 不会向外抛出,而是显示我们自定义的信息.

我们可以根据这个原理自定义如何处理异常,只要将返回值设置为True就行了.

代码语言:javascript
复制
class OpenFile(object):
    """自定义上下文管理类"""
 
    def __init__(self, file, mode):
        self._file = file
        self._mode = mode
 
    def __enter__(self):
        self._handle = open(self._file, self._mode)
        return self._handle
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        self._handle.close()
        # 通过exc_type参数接收到的值,来判断程序执行是否出现异常
        # 如果是None,说明没有异常
        if exc_type == "None":
            print('正常执行')
        else:
            # 否则出现异常,可以选择怎么处理异常
            print(exc_type, exc_val)
        # 返回值决定了捕获的异常是否继续向外抛出
        # 如果是False那么就会继续向外抛出,程序会看到系统提示的异常信息
        # 如果是True不会向外抛出,程序看不到系统提示信息,只能看到else中的输出
        return True
 
 
with OpenFile('test01.txt', 'r') as f:
    f.write('自定义上下文管理\n')

通过设置返回值为True,上下文管理器不会向外抛出异常,此时我们在根据exc_type(异常类型)的值是否为"None"来自定义输出的异常信息,就可以实现上下文管理中的自定义异常了.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python 碎片 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档