Python中with用法详解
<h1><code>一 、with</code>语句的原理</h1><ul>
<li>上下文管理协议(Context Management Protocol):包含方法 <code>__enter__()</code>和<code>__exit__()</code>,支持该协议的对象要实现这两个方法。</li>
<li>上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了<code>__enter__()</code>和<code>__exit__()</code>方法。上下文管理器定义执行<code>with</code>语句时要建立的运行时上下文,负责执行<code>with</code>语句块上下文中的进入与退出操作。通常使用<code>with</code>语句调用上下文管理器,也可以通过直接调用其方法来使用。</li>
</ul>
<p>说完上面两个概念,我们再从<code>with</code>语句的常用表达式入手,一段基本的<code>with</code>表达式,其结构是这样的:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">with EXPR as VAR:
</span><span style="color: rgba(0, 128, 128, 1)">2</span>
<span style="color: rgba(0, 128, 128, 1)">3</span> BLOCK</pre>
</div>
<p>其中EXPR可以是任意表达式;as VAR是可选的。其一般的执行过程是这样的:</p>
<ol>
<li>执行EXPR,生成上下文管理器context_manager;</li>
<li>获取上下文管理器的<code>__exit()__</code>方法,并保存起来用于之后的调用;</li>
<li>调用上下文管理器的<code>__enter__()</code>方法;如果使用了<code>as</code>子句,则将<code>__enter__()</code>方法的返回值赋值给<code>as</code>子句中的VAR;</li>
<li>执行BLOCK中的表达式;</li>
<li>不管是否执行过程中是否发生了异常,执行上下文管理器的<code>__exit__()</code>方法,<code>__exit__()</code>方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句<code>break/continue/return</code>,则以<code>None</code>作为参数调用<code>__exit__(None, None, None)</code>;如果执行过程中出现异常,则使用<code>sys.exc_info</code>得到的异常信息为参数调用<code>__exit__(exc_type, exc_value, exc_traceback)</code>;</li>
<li>出现异常时,如果<code>__exit__(type, value, traceback)</code>返回False,则会重新抛出异常,让<code>with</code>之外的语句逻辑来处理异常,这也是通用做法;如果返回True,则忽略异常,不再对异常进行处理。</li>
</ol>
<h1>二、自定义上下文管理器</h1>
<p><code> Python</code>的<code>with</code>语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> coding = utf-8</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 2019/7/19Luckyxxt:有趣的事,Python永远不会缺席!</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">!/usr/bin/env python</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> DBManager(object):
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span><span style="color: rgba(0, 0, 0, 1)">(self):
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">pass</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__enter__</span><span style="color: rgba(0, 0, 0, 1)">(self):
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">__enter__</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> self
</span><span style="color: rgba(0, 128, 128, 1)">12</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__exit__</span><span style="color: rgba(0, 0, 0, 1)">(self, exc_type, exc_val, exc_tb):
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">__exit__</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> True
</span><span style="color: rgba(0, 128, 128, 1)">16</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> getInstance():
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> DBManager()
</span><span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)">with getInstance() as dbManagerIns:
</span><span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">with demo</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p><strong> with后面必须跟一个上下文管理器,如果使用了as,则是把上下文管理器的 __enter__() 方法的返回值赋值给 target,target 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)</strong></p>
<p>代码运行结果如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(128, 0, 0, 1)">'''</span>
<span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(128, 0, 0, 1)">__enter__
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(128, 0, 0, 1)">with demo
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(128, 0, 0, 1)">__exit__
</span><span style="color: rgba(0, 128, 128, 1)">5</span>
<span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(128, 0, 0, 1)">'''</span></pre>
</div>
<p><span style="color: rgba(128, 0, 0, 1)">结果分析:</span>当我们使用with的时候,__enter__方法被调用,并且将返回值赋值给as后面的变量,并且在退出with的时候自动执行__exit__方法</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> With_work(object):
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__enter__</span><span style="color: rgba(0, 0, 0, 1)">(self):
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">进入with语句的时候被调用</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">enter called</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">xxt</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__exit__</span><span style="color: rgba(0, 0, 0, 1)">(self, exc_type, exc_val, exc_tb):
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">离开with的时候被with调用</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">exit called</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">with With_work() as f:
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 255, 1)">print</span><span style="color: rgba(0, 0, 0, 1)">(f)
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello with</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(128, 0, 0, 1)">'''</span>
<span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(128, 0, 0, 1)">enter called
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(128, 0, 0, 1)">xxt
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(128, 0, 0, 1)">hello with
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(128, 0, 0, 1)">exit called
</span><span style="color: rgba(0, 128, 128, 1)">6</span>
<span style="color: rgba(0, 128, 128, 1)">7</span> <span style="color: rgba(128, 0, 0, 1)">'''</span></pre>
</div>
<p> </p>
<h1>三、总结</h1>
<p> 自定义上下文管理器来对软件系统中的资源进行管理,比如数据库连接、共享资源的访问控制等。</p>
<p> </p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
<strong>欢迎关注小婷儿的博客:</strong><br>
文章内容来源于小婷儿的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
有趣的事,Python永远不会缺席!<br>
如需转发,请注明出处:小婷儿的博客python https://www.cnblogs.com/xxtalhr/<br>
博客园:https://www.cnblogs.com/xxtalhr/<br>
CSDN:https://blog.csdn.net/u010986753<br>
<strong>有问题请在博客下留言或加作者:</strong><br>
微信:tinghai87605025 <br>
QQ :87605025<br>
python QQ交流群:py_data 483766429<br>
<div align="center">
<img src="https://img2018.cnblogs.com/blog/1400528/201905/1400528-20190519213410020-442219723.png" width="800" height="300" align="center">
</div><br>
<strong>培训说明:</strong><br>
OCP培训说明连接:https://mp.weixin.qq.com/s/2cymJ4xiBPtTaHu16HkiuA<br>
OCM培训说明连接:https://mp.weixin.qq.com/s/7-R6Cz8RcJKduVv6YlAxJA<br>
小婷儿的python正在成长中,其中还有很多不足之处,随着学习和工作的深入,会对以往的博客内容逐步改进和完善哒。重要的事多说几遍。。。。。。<br><br>
来源:https://www.cnblogs.com/pythonbao/p/11211347.html
頁:
[1]