python3--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语句在执行时,调用上下文管理器中的 enterexit 两个方法,这两个方法就是上下文管理器中实现的方法.

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

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

四、自定义上下文管理器

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

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

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
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"来自定义输出的异常信息,就可以实现上下文管理中的自定义异常了.
————————————————
版权声明:本文为CSDN博主「Python碎片」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43790276/article/details/90216525

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值