Python with语句和上下文管理器
Python中的with语句和上下文管理器,是从2.5版本开始加入到Python语法中的。
它能够让你的代码可读性更强并且错误更少。
一、with语法:
基本语法格式:
with EXPR as VAR:
BLOCK
2.1:普通栗子:
举个文件写入时的栗子,看简单看一下try、except、else、finally执行的顺序:
try:
f = open('test.txt', 'w')
print('__执行:try__')
# 捕捉异常
except KeyError:
print('__执行:except__')
else:
f.write('—往文件里面写内容咯')
print('__执行:else__')
finally:
f.close()
print('__无论以上发生了什么, 都会走到这里!__')
# 输出结果:
__执行:try__
__执行:else__
__无论以上发生了什么, 都会走到这里!__
以上栗子可以看出,try中的代码执行后,如果没有发生异常,那么会执行else中的代码,最后会执行finally,如果try中代码抛出了异常,那么执行顺序是怎样的呢?
try:
f = open('test.txt', 'w')
print('__执行:try__')
# 自定义抛出一个异常
raise KeyError
# 捕捉异常
except KeyError:
print('__执行:except__')
else:
f.write('—往文件里面写内容咯')
print('__执行:else__')
finally:
f.close()
print('__无论以上发生了什么, 都会走到这里!__')
# 输出结果:
__执行:try__
__执行:except__
__无论以上发生了什么, 都会走到这里!__
以上结果可以看出,在try中代码抛出了异常,那么会走except中的代码,不会走else中的代码,最后也会走finally中的代码。
有没有简单的写法呢?这样写一坨肯定不符合Python的优雅。
2.2:使用with栗子:
with open('text.txt', 'w') as f:
f.write('-往文件里面开始写内容咯-')
解释用法:with关键字,后面的open方法的返回值赋值给变量f,当离开with代码块的时候,系统会自动调用f.close()方法,with的作用和使用try,finally语句是一样的
,下面来看看它的原理。
二、上下文管理简单介绍:
上下文管理器指的是在一段代码执行之前执行一段代码,做一些预处理工作,执行之后在执行一段代码,做一些清理工作
,比如:
1.文件操作:打开文件进行读写、读写完后将文件进行关闭。
2.数据库操作:操作之前需要连接数据库,操作之后关闭连接数据库。
3.Socket操作:操作之前创建连接,操作之后关闭连接。
等等…
创建连接是一种非常昂贵的资源,不要无限的创建而不是去释放
简单的说,上下文管理器内部实现__ enter__ 和 __ exit __ 方法的对象
都可以称为上下文管理器
,上下文管理对象可以使用with关键字
。
举个栗子:
class WriteFile(object):
def __init__(self, file_name, method):
self.file_name = file_name
self.method = method
def __enter__(self):
print('__执行enter方法__')
self.f = open(self.file_name, self.method)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
print('__执行exit方法__')
self.f.close()
with WriteFile('test.txt', 'w') as f:
f.write('往文件里面写数据哦')
# 输出结果:
__执行enter方法__
__执行exit方法__
__ enter __ 方法返回资源对象,就是open()方法打开那个文件对象, __ exit __ 方法处理一些释放的工作
1.调用__ enter __ 方法,执行一些预处理工作
2.as f 也可以省略,如果不省略,将 __ enter __ 方法的返回值赋值给 f
3.执行f.write()代码块
4.调用 __ exit __ 方法,有三个参数, exc_type, exc_val, exc_tb,若代码块发生异常并退出,那么分别对应异常的type、value 和 traceback。否则三个参数全为None
5.__ exit __ 方法的返回值可以为True或者False,如果为True,那么表示异常被忽视,相当于进行了try-except操作,如果为False,异常会被重新raise
因为WriteFile类实现上下文管理器,所以我们可以使用with语句
三、使用contextlib库:
Python提供内置的contextlib库,使上下文管理器更加容易使用。
简单理解:通过yield
将函数分割成两部分,yield
之前语句在 __ enter __ 方法中执行,yield
之后的语句在 __ exit __ 方法中执行,yield 后面的值是函数的返回值
from contextlib import contextmanager
@contextmanager
def write_file(file_name, method):
f = open(file_name, method) # 执行 __enter__ 方法
yield f # 将f返回
f.close() # 执行 __exit__ 方法
with write_file('test.txt', 'w') as f:
# f.write() 调用该write()方法
f.write('往文件里面写东西咯!')