【python】with…as语句——基于上下文管理器的操作

导读:本篇文章讲解 【python】with…as语句——基于上下文管理器的操作,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

with介绍

with语句如何工作

__exit__()方法说明

with中包含多个项


with语句简化公共资源的管理。使用with的代码更清晰,更具有可读性。

with介绍

先看一个写入文件的例子,常规的写入文件步骤是:打开文件;写入文件;关闭文件,代码如下:

# 常规的文件操作
fd = open('tmp.txt','w+')
fd.write('hello python')
fd.close()

如果在文件写入过程中出现异常,那么close()方法将无法被执行,tmp.txt文件会被程序一直占用无法被释放掉。

然后就会想到可以用捕获异常的方式来处理这种问题,代码如下:

# 异常捕获机制处理文件操作
try:
    fd = open('tmp.txt','w+')
    fd.write('hello python')
except Exception as e:
    print(e)
else:
    pass
finally:
    fd.close()

但是感觉代码有点冗余。如果使用with语句,代码如下:

# with语句进行文件操作
with open('tmp.txt','w+') as f:
    f.write('hello python')

使用两行语句即可处理。因为使用with关键字后系统会自动调用f.close()方法,with的作用等效于try/finally语句。

with语句的实现是建立在上下文管理器上的。

上下文管理器是一个实现_enter_和_exit_的方法的类。使用with语句可以确保在嵌套块的末尾调用_exit_方法。

上下文管理器首先调用__enter__方法,然后执行with语句中的代码,最后调用__exit__方法,即使出现错误,也会调用__exit__方法,即关闭文件流。

执行如下代码,显示结果,可以看到文件对象中实现了__enter__和__exit__方法,即文件对象也实现了上下文管理器

fd = open('tmp.txt','r')
print(dir(fd))
fd.close()

[‘_CHUNK_SIZE’, ‘__class__’, ‘__del__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__enter__‘, ‘__eq__’, ‘__exit__‘, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__init_subclass__’, ‘__iter__’, ‘__le__’, ‘__lt__’, ‘__ne__’, ‘__new__’, ‘__next__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘_checkClosed’, ‘_checkReadable’, ‘_checkSeekable’, ‘_checkWritable’, ‘_finalizing’, ‘buffer’, ‘close’, ‘closed’, ‘detach’, ‘encoding’, ‘errors’, ‘fileno’, ‘flush’, ‘isatty’, ‘line_buffering’, ‘mode’, ‘name’, ‘newlines’, ‘read’, ‘readable’, ‘readline’, ‘readlines’, ‘reconfigure’, ‘seek’, ‘seekable’, ‘tell’, ‘truncate’, ‘writable’, ‘write’, ‘write_through’, ‘writelines’]

with语句如何工作

  • 首先执行紧跟with的语句,如上示例中的 open(‘tmp.txt’,’w+’),该语句会返回一个对象,对象的__enter__方法被调用,__enter__方法的返回值赋值给as后面的变量;
  • 然后执行with后面的嵌套块中的语句;
  • 最后会调用前面返回的对象的__exit__方法;

为了更直观的说明,可以看如下实例

class MyManagement(object):
    
    
    def __enter__(self):
        print('__enter__ 被调用')
        return self

    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__ 被调用')
    

    def show(self):
        print('show 被调用')


if __name__ == '__main__':
    with MyManagement() as m:
        m.show()
    

输出结果,可以看到输出顺序是 __enter__()  →  嵌套块执行    →    __exit__()。

__enter__ 被调用
show 被调用
__exit__ 被调用

__exit__()方法说明

__exit__()方法中有三个参数,exc_type,exc_val,exc_tb,这三个参数和异常抛出相关联。当with嵌套块语句中有任何异常时,__exit__()方法都会被执行。

如下示例:
 

class MyManagement(object):
    
    
    def __enter__(self):
        print('__enter__ 被调用')
        return self

    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__ 被调用')
    

    def show(self):
        print('show 被调用',1/0)


if __name__ == '__main__':
    with MyManagement() as m:
        m.show()
    

在show()方法中,1/0会抛出异常,显示结果

__enter__ 被调用
__exit__ 被调用
Traceback (most recent call last):
  File “e:/1_tempFile/1_learn_code/VSCode/python_test/python_files/with.py”, line 19, in <module>
    m.show()
  File “e:/1_tempFile/1_learn_code/VSCode/python_test/python_files/with.py”, line 14, in show
    print(‘show 被调用’,1/0)
ZeroDivisionError: division by zero

如果需要跳过某种异常,可以使__exit__()函数返回True。如下,跳过所有的TypeError,其它异常正常抛出。

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__ 被调用')
        return isinstance(exc_val,TypeError)

使用with语句对异常进行处理还可以参考如下写:

try:
    with open('a.txt') as f:
        # 执行语句
except xxxError:
    # 执行一些异常处理语句

with中包含多个项

如果有多个项,可以按照如下写:

with open('1.txt') as f1, open('2.txt') as f2:
    # 执行语句

参考:python的with用法 | kissdata

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/46085.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!