Python--with使用&&魔术方法
逛Github的一些Python项目的时候看到了用with来处理读写文件就顺便来看一下:
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。
读写文件
先看看读写文件的语句语法
# Python3 open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
mode则可以为:
文件打开模式 | 描述 |
---|---|
r | 以只读模式打开文件,并将文件指针指向文件头;如果文件不存在会报错 |
w | 以只写模式打开文件,并将文件指针指向文件头;如果文件存在则将其内容清空,如果文件不存在则创建 |
a | 以只追加可写模式打开文件,并将文件指针指向文件尾部;如果文件不存在则创建 |
r+ | 在r的基础上增加了可写功能 |
w+ | 在w的基础上增加了可读功能 |
a+ | 在a的基础上增加了可读功能 |
b | 读写二进制文件(默认是t,表示文本),需要与上面几种模式搭配使用,如ab,wb, ab, ab+(POSIX系统,包括Linux都会忽略该字符) |
r+、w+和a+都可以实现对文件的读写,那么他们有什么区别呢?
- r+会覆盖当前文件指针所在位置的字符,如原来文件内容是"Hello,World",打开文件后写入"hi"则文件内容会变成"hillo, World"
- w+与r+的不同是,w+在打开文件时就会先将文件内容清空,不知道它有什么用
- a+与r+的不同是,a+只能写到文件末尾(无论当前文件指针在哪里)
首先在Python项目下没有这个txt文件
然后试着读写运行
没有输出,说明很显然他是没有去执行这个file.close()的,没有关闭文件句柄。
出现异常可以想到使用try:
try: file = open("test.txt") except: print("file open failed!") try: renew = file.read() except: print("空的file") finally: file.close()
这样写就能释放资源,关闭文件句柄,但是很繁琐,Python中可以用with来实现。
with open("test.txt") as file: renew = file.read()
with 工作原理
(1)紧跟with后面的语句被求值后,返回对象的“__enter__()”方法被调用,这个方法的返回值将被赋值给as后面的变量;
(2)当with后面的代码块全部被执行完之后,将调用前面返回对象的“__exit__()”方法。
这种函数写法是不是很熟悉,这就是Python中的魔术方法!
工作原理代码示例:
class Sample(): def __enter__(self): print('in enter') return self # def __exit___(self,a,b,c): # print(a,b,c) def __exit__(self, exc_type, exc_val, exc_tb): print("type: ", exc_type) print("val: ", exc_val) print("tb: ", exc_tb) def do_something(self): bar = 1 / 0 return bar + 10 with Sample() as sample: sample.do_something()
运行结果:
说一下这个代码,使用with来实例化Sample类创建sample对象,
用该对象去调用内置方法,然后__enter__魔术方法先触发,所以打印了in enter
然后回到do_something方法执行,显然1/0是错误的 return完后触发__exit__打印异常信息。
顺便说下__exit__方法中的这个三个参数‘exc_type, exc_val, exc_tb’,
异常类型,异常值和异常的trackback
如果with语发生异常,但不希望抛出,__exit__方法应该返回return True,相当于with语句自动做一个try,except处理,
class WithContext(object): def __init__(self, name=None): self.name = name print('接收参数:%r' % name) def with_context(self): print(self.name) print('调用with方法') def __enter__(self): print('调用enter方法') return self def __exit__(self, exc_type, exc_val, exc_tb): print(exc_type, exc_val, exc_tb) print('调用exit方法') return True # return True if __name__ == '__main__': # 'test'作为参数传递给__init__方法 # w为__enter__方法的返回值 with WithContext('test') as w: # 发生异常 a = 1 / 0 # a=1/0
运行结果不会打印出了trackback,因为设置了__exit__ return true
如果不return true,打印出了Traceback
魔术方法之前已经有过了解
详细可以参考这里