加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

上下文管理器——with语句的实现

发布时间:2020-12-17 00:17:45 所属栏目:Python 来源:网络整理
导读:div class="markdown-here-wrapper" data-md-url="https://i.cnblogs.com/EditPosts.aspx?opt=1"gt; h1 id="-" style="margin: 20px 0px 10px; padding: 0px; font-weight: bold; color: black; font-size: 24px; border-bottom: 2px solid #aaaaaa;"前言 p

<div class="markdown-here-wrapper" data-md-url="https://i.cnblogs.com/EditPosts.aspx?opt=1"&gt;
<h1 id="-" style="margin: 20px 0px 10px; padding: 0px; font-weight: bold; color: black; font-size: 24px; border-bottom: 2px solid #aaaaaa;">前言
<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">with语句的使用给我们带来了很多的便利,最常用的可能就是关闭一个文件,释放一把锁。


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">既然with语句这么好用,那我也想让我自己写的代码也能够使用with语句,该怎么实现?


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">下面具体介绍怎样实现一个自己的with语句


<h1 id="-" style="margin: 20px 0px 10px; padding: 0px; font-weight: bold; color: black; font-size: 24px; border-bottom: 2px solid #aaaaaa;">使用类实现
<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">要想使用with语句,那就要遵循with语句的使用规矩,也就是上下文管理器协议


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">这个协议提示我们要在类中去实现两个特殊方法,<strong style="color: #bf360c;">enter(self)和<strong style="color: #bf360c;">exit(self,exc_type,exc_val,exc_tb)


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">有了这两个方法,就可以使用with语句执行了,它的执行过程为先执行<strong style="color: #bf360c;">enter(self)方法,然后执行你添加在with下的代码,然后最后执行<strong style="color: #bf360c;">exit方法


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">如果在执行的过程中出现了异常,那么会自动执行<strong style="color: #bf360c;">exit方法,

 :
     :
        
<span class="hljs-function" style="color: #bbdaff;"&gt;<span class="hljs-keyword" style="color: #ebbbff;"&gt;def</span> <span class="hljs-title" style="color: #7285b7;"&gt;produce</span><span class="hljs-params" style="color: #ffc58f;"&gt;(self)</span>:</span>
    <span class="hljs-keyword" style="color: #ebbbff;"&gt;raise</span> RuntimeError(<span class="hljs-string" style="color: #d1f1a9;"&gt;'ERROR'</span>)

<span class="hljs-class"><span class="hljs-keyword" style="color: #ebbbff;">class <span class="hljs-title" style="color: #7285b7;">MyWith:
<span class="hljs-function" style="color: #bbdaff;"><span class="hljs-keyword" style="color: #ebbbff;">def <span class="hljs-title" style="color: #7285b7;">enter<span class="hljs-params" style="color: #ffc58f;">(self):
<span class="hljs-keyword" style="color: #ebbbff;">return ErrorProduce()

<span class="hljs-function" style="color: #bbdaff;"&gt;<span class="hljs-keyword" style="color: #ebbbff;"&gt;def</span> <span class="hljs-title" style="color: #7285b7;"&gt;__exit__</span><span class="hljs-params" style="color: #ffc58f;"&gt;(self,exc_tb)</span>:</span>
    <span class="hljs-keyword" style="color: #ebbbff;"&gt;if</span> exc_type:
        print(<span class="hljs-string" style="color: #d1f1a9;"&gt;"有错"</span>)
        <span class="hljs-comment" style="color: #7285b7;"&gt;#print(exc_val)</span>
        <span class="hljs-comment" style="color: #7285b7;"&gt;#return True</span>
    <span class="hljs-keyword" style="color: #ebbbff;"&gt;else</span>:
        print(<span class="hljs-string" style="color: #d1f1a9;"&gt;"完美执行"</span>)

<span class="hljs-keyword" style="color: #ebbbff;">with MyWith() <span class="hljs-keyword" style="color: #ebbbff;">as E:
E.produce()


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">将上述代码运行,会先打印出“有错”,然后再打印出相关错误,然后程序由于错误终止,也就是说,在产生了错误后,还是执行了exit中的代码


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">如果将exit中的两个注释符号去掉的话,那么再次运行程序不会报错,但会将exc_val中的错误信息打印出来,这里相当于通过exit方法将错误抹除掉了,抹除方式为返回True,但也把with中抛出错误后的所有代码都跳过了。


<h1 id="-" style="margin: 20px 0px 10px; padding: 0px; font-weight: bold; color: black; font-size: 24px; border-bottom: 2px solid #aaaaaa;">使用函数实现
<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">通过引入contextlib模块中的contextmanager装饰器,装饰函数使函数可以使用with语句

 contextlib  contextmanager

<span class="hljs-class"><span class="hljs-keyword" style="color: #ebbbff;">class <span class="hljs-title" style="color: #7285b7;">ErrorProduce:
<span class="hljs-function" style="color: #bbdaff;"><span class="hljs-keyword" style="color: #ebbbff;">def <span class="hljs-title" style="color: #7285b7;">init<span class="hljs-params" style="color: #ffc58f;">(self):
<span class="hljs-keyword" style="color: #ebbbff;">pass

<span class="hljs-function" style="color: #bbdaff;"&gt;<span class="hljs-keyword" style="color: #ebbbff;"&gt;def</span> <span class="hljs-title" style="color: #7285b7;"&gt;produce</span><span class="hljs-params" style="color: #ffc58f;"&gt;(self)</span>:</span>
    <span class="hljs-keyword" style="color: #ebbbff;"&gt;raise</span> RuntimeError(<span class="hljs-string" style="color: #d1f1a9;"&gt;'ERROR'</span>)

<span class="hljs-decorator">@contextmanager
<span class="hljs-function" style="color: #bbdaff;"><span class="hljs-keyword" style="color: #ebbbff;">def <span class="hljs-title" style="color: #7285b7;">my_with<span class="hljs-params" style="color: #ffc58f;">():
<span class="hljs-keyword" style="color: #ebbbff;">try:
<span class="hljs-keyword" style="color: #ebbbff;">yield ErrorProduce()
<span class="hljs-keyword" style="color: #ebbbff;">except Exception <span class="hljs-keyword" style="color: #ebbbff;">as e:
print(e)
     <span class="hljs-comment" style="color: #7285b7;">#raise
<span class="hljs-keyword" style="color: #ebbbff;">finally:
print(<span class="hljs-string" style="color: #d1f1a9;">'收尾')

<span class="hljs-keyword" style="color: #ebbbff;">with my_with() <span class="hljs-keyword" style="color: #ebbbff;">as E:
E.produce()
print(<span class="hljs-string" style="color: #d1f1a9;">'aa')


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">函数中使用了yield,那么它也就变成了生成器,通过yield来划分相当于类中的enter和exit,yield返回的值也就是可以用作as后的值


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">上段代码中我们发现使用了try,except,finally异常处理的语句,这些语句是必要的吗?


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">通过测试,如果没有这些异常处理,那么with语句还是可以执行的,这里的意思是可以使用with语句,不会报不能使用with的错误,但是使用后,只有with下的语句中没有抛出异常,那么yield语句后边的代码才会执行,一旦有异常抛出,仍然是程序运行终止。所以,一般还是要配合try,except,finally语句来构造。


<p style="margin: 0px 0px 1.2em !important; font-size: 16px; line-height: 1.75em; padding-right: 0.5em; padding-left: 0.5em;">还有一点要注意,使用这种方式,异常被except捕捉后,那么这个异常就失效了,一般的我们还是会需要在except中再次将捕捉的异常抛出,也就是在后面加上raise,因为我们使用with只是为了做好一个收尾,如关闭文件句柄。或者另一种方式,我们干脆就不写except语句,直接写finally语句了。


(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读