<ol>
<li><p>我相信在我之前,其他用户已经回答过这个问题,所以我添加它只是为了完整性:语句<code>with</code>通过将常见的准备和清理任务封装在所谓的<a href="http://docs.python.org/release/2.5.2/lib/typecontextmanager.html" rel="noreferrer">context managers</a>中,简化了异常处理。更多详细信息请参见<a href="http://www.python.org/dev/peps/pep-0343/" rel="noreferrer">PEP 343</a>。例如,<code>open</code>语句本身就是一个上下文管理器,它允许您打开一个文件,只要执行是在使用它的<code>with</code>语句的上下文中,就保持它的打开状态,并在离开上下文时立即将其关闭,无论您是因为异常还是在常规控制流期间离开了它。因此,{{CD1}}语句可以以类似于C++中的{{a3}的方式使用:一些资源是由^ {< CD1> }语句获取的,并且在离开^ {< CD1> }上下文时释放。</p></li>
<li><p>例如:使用<code>with open(filename) as fp:</code>打开文件,使用<code>with lock:</code>获取锁(其中<code>lock</code>是<code>threading.Lock</code>的实例)。您还可以使用<code>contextlib</code>中的<code>contextmanager</code>装饰器构造自己的上下文管理器。例如,当我必须临时更改当前目录,然后返回到原来的位置时,我经常使用此选项:</p>
<pre><code>from contextlib import contextmanager
import os
@contextmanager
def working_directory(path):
current_dir = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(current_dir)
with working_directory("data/stuff"):
# do something within data/stuff
# here I am back again in the original working directory
</code></pre>
<p>下面是另一个临时将<code>sys.stdin</code>、<code>sys.stdout</code>和<code>sys.stderr</code>重定向到其他文件句柄并稍后还原它们的示例:</p>
<pre><code>from contextlib import contextmanager
import sys
@contextmanager
def redirected(**kwds):
stream_names = ["stdin", "stdout", "stderr"]
old_streams = {}
try:
for sname in stream_names:
stream = kwds.get(sname, None)
if stream is not None and stream != getattr(sys, sname):
old_streams[sname] = getattr(sys, sname)
setattr(sys, sname, stream)
yield
finally:
for sname, stream in old_streams.iteritems():
setattr(sys, sname, stream)
with redirected(stdout=open("/tmp/log.txt", "w")):
# these print statements will go to /tmp/log.txt
print "Test entry 1"
print "Test entry 2"
# back to the normal stdout
print "Back to normal stdout again"
</code></pre>
<p>最后,另一个创建临时文件夹并在离开上下文时将其清除的示例:</p>
<pre><code>from tempfile import mkdtemp
from shutil import rmtree
@contextmanager
def temporary_dir(*args, **kwds):
name = mkdtemp(*args, **kwds)
try:
yield name
finally:
shutil.rmtree(name)
with temporary_dir() as dirname:
# do whatever you want
</code></pre></li>
</ol>