Python进阶系列(十八)

举报
zhulin1028 发表于 2022/06/28 01:05:14 2022/06/28
【摘要】 处理异常 我们还没有谈到__exit__方法的这三个参数:type, value和traceback。 在第4步和第6步之间,如果发生异常,Python会将异常的type,value和traceback传递给__exit__方法。 它让__exit__方法来决定如何关闭文件以及是否需要其他步骤。在我们的案例中,我们并没有注意它...

处理异常

我们还没有谈到__exit__方法的这三个参数:type, value和traceback。

在第4步和第6步之间,如果发生异常,Python会将异常的type,value和traceback传递给__exit__方法。

它让__exit__方法来决定如何关闭文件以及是否需要其他步骤。在我们的案例中,我们并没有注意它们。

那如果我们的文件对象抛出一个异常呢?万一我们尝试访问文件对象的一个不支持的方法。举个例子:


  
  1. with File('demo.txt', 'w') as opened_file:
  2.     opened_file.undefined_function('Hola!')

我们来列一下,当异常发生时,with语句会采取哪些步骤。

    1. 它把异常的type,value和traceback传递给__exit__方法

    2. 它让__exit__方法来处理异常

    3. 如果__exit__返回的是True,那么这个异常就被优雅地处理了。

    4. 如果__exit__返回的是True以外的任何东西,那么这个异常将被with语句抛出。

在我们的案例中,__exit__方法返回的是None(如果没有return语句那么方法会返回None)。因此,with语句抛出了那个异常。

Traceback (most recent call last):File "<stdin>", line 2, in <module>

AttributeError: 'file' object has no attribute 'undefined_function'

我们尝试下在__exit__方法中处理异常:


  
  1. class File(object):
  2.     def __init__(self, file_name, method):
  3.         self.file_obj = open(file_name, method)
  4.     def __enter__(self):
  5.         return self.file_obj
  6.     def __exit__(self, type, value, traceback):
  7.         print("Exception has been handled")
  8.         self.file_obj.close()
  9.         return True
  10. with File('demo.txt', 'w') as opened_file:
  11.     opened_file.undefined_function()
  12. # Output: Exception has been handled

我们的__exit__方法返回了True,因此没有异常会被with语句抛出。

这还不是实现上下文管理器的唯一方式。还有一种方式,我们会在下一节中一起看看。

基于生成器的实现

我们还可以用装饰器(decorators)和生成器(generators)来实现上下文管理器。

Python有个contextlib模块专门用于这个目的。我们可以使用一个生成器函数来实现一个上下文管理器,而不是使用一个类。

让我们看看一个基本的,没用的例子:


  
  1. from contextlib import contextmanager
  2. @contextmanager
  3. def open_file(name):
  4.     f = open(name, 'w')
  5.     yield f
  6.     f.close()

OK啦!这个实现方式看起来更加直观和简单。然而,这个方法需要关于生成器、yield和装饰器的一些知识。在这个例子中我们还没有捕捉可能产生的任何异常。它的工作方式和之前的方法大致相同。

让我们小小地剖析下这个方法。

1. Python解释器遇到了yield关键字。因为这个缘故它创建了一个生成器而不是一个普通的函数。

2. 因为这个装饰器,contextmanager会被调用并传入函数名(open_file)作为参数。

3. contextmanager函数返回一个以GeneratorContextManager对象封装过的生成器。

4. 这个GeneratorContextManager被赋值给open_file函数,我们实际上是在调用GeneratorContextManager对象。

那现在我们既然知道了所有这些,我们可以用这个新生成的上下文管理器了,像这样:


  
  1. with open_file('some_file') as f:
  2.     f.write('hola!')

至此,Python进阶已结束,感谢支持。

文章来源: zhulin1028.blog.csdn.net,作者:zhulin1028,版权归原作者所有,如需转载,请联系作者。

原文链接:zhulin1028.blog.csdn.net/article/details/125112227

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。