<p><code>yield</code>表达式将控制权返回给使用生成器的对象。生成器在此时暂停</em>,这意味着<code>@contextmanager</code>修饰符知道代码是用<em>设置</em>部分完成的。在</p>
<p>换句话说,在上下文管理器<code>__enter__</code>阶段中要做的一切都必须在<code>yield</code>之前发生。在</p>
<p>一旦上下文退出(因此<code>with</code>语句下的块完成),将为上下文管理器协议的<code>__exit__</code>部分调用<code>@contextmanager</code>修饰符,并将执行以下两种操作之一:</p>
<ul>
<li><p>如果没有异常,它会恢复你的生成器。因此,生成器在<code>yield</code>行取消暂停,然后进入<em>清理阶段</em>,该部分</p></li>
<li><p>如果出现异常,装饰器使用<code>generator.throw()</code>在生成器中引发该异常。就好像<code>yield</code>行导致了这个异常。因为您有一个<code>finally</code>子句,它将在生成器因异常而退出之前执行。</p></li>
</ul>
<p>因此,在您的具体例子中,顺序如下:</p>
<ol>
<li><p><code>with time_print("processes"):</code></p>
<p>这将创建上下文管理器并调用<code>__enter__</code>。</p></li>
<li><p>生成器开始执行,<code>t = time.time()</code>运行。</p></li>
<li><p><code>yield</code>表达式暂停生成器,控制返回到装饰器。这将获取所生成的任何内容并将其返回到<code>with</code>语句,以防存在<code>as target</code>部分。这里生成<code>None</code>(只有一个普通的<code>yield</code>表达式)。</p></li>
<li><p><code>[doproc() for _ in range(500)]</code>运行并完成。</p></li>
<li><p>上下文管理器<code>__exit__</code>方法已运行,未传入异常。</p></li>
<li><p>装饰者重新启动生成器,它继续执行它停止的地方。</p></li>
<li><p>输入<code>finally:</code>块并执行<code>print task_name, "took", time.time() - t, "seconds."</code>。</p></li>
<li><p>生成器退出,decorator <code>__exit__</code>方法退出,一切都完成了。</p></li>
</ol>