python中的上下文管理器_Python中的上下文管理器

操作文件对象时可以:

with open('a.txt') as f:

'代码块'

上述叫做上下文管理协议,即with语句。

想象一下,你有两个需要结对执行的相关操作,然后,还要在他们中间放置一段代码。比如打开一个文件,操作文件,然后关闭该文件。

打开文件和关闭文件就是一个结对的操作。

上下文管理器的常见用例:是资源的加锁与解锁,文件的打开与关闭。

上下文管理器

上下文管理器协议:是指类需要实现 __ enter __ 和 __ exit __ 方法。

就跟迭代器有迭代器协议一样,迭代器协议需要实现 __ iter __ 和 __ next __ 方法。

上下文管理器,也就是支持上下文管理协议的对象,简单点讲就是,实现了 __ enter __ 和 __ exit __两个方法的类。这个类也叫做,上下文管理器的类。

写一个Open类,这个类是一个上下文管理器:

class Open:

def __init__(self, filepath, encoding):

self.filepath = filepath

self.encoding = encoding

def __enter__(self): # 当这个类被with关键字执行时,就自动调用这个方法。有返回值则调用给 as 声明的变量

print('当这个类被with关键字执行时,就自动调用这个方法。有返回值则调用给 as 声明的变量')

def __exit__(self, exc_type, exc_val, exc_tb):

print('with 中代码块执行完就执行我这个函数')

with Open('1.txt', 'UTF-8') as f:

print('with 里面的代码块')

'''

结果:

当这个类被with关键字执行时,就自动调用这个方法。有返回值则调用给 as 声明的变量

with 里面的代码块

with 中代码块执行完就执行我这个函数

'''

__ exit __(self, exc_type, exc_val, exc_tb):

里面的三个参数分别代表:异常类型,异常值,追溯信息。

注意:with语句中的代码块出现异常后,with后的代码都无法执行

基于类的实现:完整实现Open方法

一个上下文管理器的类,起码要定义 __ enter __ 和 __ exit __ 方法。

class Open:

def __init__(self, filepath, method):

self.file = open(filepath, method, encoding='utf-8')

def __enter__(self):

return self.file

def __exit__(self, type, value, traceback):

self.file.close()

with Open('1.txt', 'w') as f:

f.write('1111111111')

我们来看看底层发生了什么?

with语句先暂存了 Open 类的 __ exit __ 方法

然后调用 Open 类的 __ enter __ 方法

__ enter __ 方法打开文件并返回给with语句

打开的文件句柄传递给 as 后面的 f 参数

执行with里面的代码块。

调用之前暂存的 __ exit __ 方法

关闭文件

在第4步和第6步之间,如果发生异常,Python会将异常的type,value,traceback传递给 __ exit __ 方法。

当异常发生时,with语句会采取哪些步骤?

with把异常的type, value, traceback 传递给 __ exit __ 方法

with让 __ exit __ 处理异常

如果 __ exit __ 返回的是True, 那么这个异常就被优雅的处理了。

如果 __ exit __ 返回的是True以外的任何东西,那个这个异常将被with 语句抛出。

当 __ exit __()返回值为True, 那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行.。

完整模拟Open:

class Open:

def __init__(self, filepath, mode='r', encoding='utf-8'):

self.filepath = filepath

self.mode = mode

self.encoding = encoding

def __enter__(self):

self.file = open(self.filepath, mode=self.mode, encoding=self.encoding)

return self.file

def __exit__(self, exc_type, exc_val, exc_tb):

print(exc_type)

self.file.close()

return True

with Open('1.txt', 'w', encoding='utf-8') as f:

f.write('哈哈哈')

f.werwer # 抛出异常,交给exit处理。后面的代码正常运行

优点

使用with的语句的目的就是把代码块放入with中执行, with结束后,自动完成清理工作,无需干预。

在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在 __ exit __ 中定制自动释放资源的机制。

基于生成器实现一个上下文管理器

contextlib模块:可以使用一个生成器实现一个上下文管理器,而不是使用一个类。众所周知,在类中还需要实现 __ enter __ 和 __ exit __ 。

from contextlib import contextmanager

@contextmanager

def point(x, y):

print('在yield之前')

yield x * y # yield出去的值赋给 as 后面的变量

print('在yield之后')

with point(3, 4) as p:

print('p',p)

'''

结果:

在yield之前

p 12

在yield之后

'''

利用contextlib模块实现一个open

@contextmanager

def my_open(path):

f = open(path, mode='w')

yield f # 把这个f 赋给as后面的变量

f.close()

with my_open('2.txt') as f:

f.write('我是你爹')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值