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

 

魔术方法之前已经有过了解

详细可以参考这里

posted @ 2021-12-22 13:27  Erichas  阅读(207)  评论(0编辑  收藏  举报