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

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

一、上下文管理器

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

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

语法: with

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

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

二、with上下文管理器示例

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__ 两个方法即可.

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 ,这三个参数是用来接收异常信息的,如果代码在运行时发生异常,异常信息会被保存到这三个参数中.

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',会出现异常,因为以读的模式打开文件,不能进行写操作.运行结果为:

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就行了.

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"来自定义输出的异常信息,就可以实现上下文管理中的自定义异常了.

 

 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小斌哥ge

非常感谢,祝你一切顺利。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值