最常见的with用法
操作文件的时候,我们经常写下如下的代码,但是你知道with的原理是什么吗?为神马要这么写吗?
with open("test.txt",mode='w') as my_file:
print("hello world")
先聊聊open()内置函数
open()内置函数会返回一个文件对象,当我们对文件对象的方法进行调用,则是对文件内容的读写,接下来我们先看一个不使用with语句操作文件的例子
不使用with操作文件?
file = open('test.txt', 'w')
file.write('hello world !')
file.close()
此时可能出现2个坑
1、你很可能会忘记调用文件对象的close()方法,导致文件句柄一直被当前进程占用着,占用的内存会延迟释放(备注:当进程结束,也会释放)
2、调用文件对象的write()方法时直接出现异常,比如磁盘满了,此时程序会因为异常没有处理被结束,后续的close()方法也不会得到执行
如何避免上面的2个坑?
file = open('test.txt', 'w')
try:
file.write('hello world')
except Exception:
print("啥也不干")
finally:
file.close()
使用try代码进行处理
1、当出现任何异常,except语句会执行
2、无论如何,finally代码块也会执行,不用担心close()不被调用
此时就有一个缺点:不够优雅,代码冗余太多
with语句,自然而然的优雅起来
with open('test.txt', 'w') as file:
file.write('hello world')
发生异常会自动被处理
文件对象会自动被关闭
你肯定想问了,with是如何做到这些的呢?这将引出一个重要的概念:上下文管理器
重要概念:上下文管理器对象
with 语句的实现原理建立在上下文管理器对象(简称上下文管理器)之上
python中有明确定义:同时实现 __enter__ 和 __exit__ 方法的对象称为上下文管理器对象
class Baby(object):
def __enter__(self):
print('===baby===')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('===close baby===')
return True
def operate(self):
temp = 1/0
return temp
同时约束__enter__方法与__exit__方法的用法
__enter__:必须返回一个对象
__exit__:必须返回boolean值,表示异常是否被处理,True表示已经处理,False表示继续抛出
__exit__的3个参数
exc_type:异常类型
exc_val:异常值
exc_tb:异常的错误栈信息
当没有异常时,自动回调时传入的都是None,存在异常时,就是说明说的3个对象
你可以执行这段代码试试,我说的对不对
with Baby() as my_baby:
baby.operate()
print("Over")
File对象是这么做的(非完整源码)
class File:
def __init__(self, file_path, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True):
self._file = open(file_path, mode=mode, buffering=buffering, encoding=encoding,
errors=errors, newline=newline, closefd=closefd)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._file.close()
#省略很多源码……
再回头with语句的工作过程
with open('test.txt', 'w') as my_file: my_file.write('hello world!')
1、open()内置函数会最先执行,它会返回一个File对象(with语句后面跟着的是上下文管理器对象即可)
2、File对象的__enter__()方法被自动调用
3、__enter__()方法的返回值赋值到as后面的变量,由于File对象的__enter__()方法返回的时self
4、上下文管理器中的代码块开始执行,即my_file.write()这行代码开始执行
5、File对象的__exit__()方法被自动调用,其中__exit__中的有close()方法的调用,文件关闭
with语句两个用途
1、释放必要资源
2、处理异常
总结
1、熟悉with语句,操作文件游刃有余
2、自己写用于with语句的对象
1307

被折叠的 条评论
为什么被折叠?



