27.7. contextlibwith-语句上下文工具

2.5版中新增.

源代码:: Lib/contextlib.py

该模块提供一些与with 语句有关的工具.更多信息请参看 上下文管理器类型 With 语句与上下文管理器.

提供的函数:

contextlib.contextmanager(func)

该函数是一个 装饰器.可以用来定义一个用于 with 语句的工厂函数, 不需要创建一个类或者单独的 __enter__()__exit__() 方法.

一个简单的示例 (真正产生HTML代码,不推荐该方法!)):

from contextlib import contextmanager

@contextmanager
def tag(name):
    print "<%s>" % name
    yield
    print "</%s>" % name

>>> with tag("h1"):
...    print "foo"
...
<h1>
foo
</h1>

上面被装饰器修饰的函数被调用的时候,必须返回一个 generator-iterator 。这个生成器必须 yield 一个确切的值, 这个值将会被绑定到 with 语句的 as 字句中的 targets, 如果有的话.

在这个生成器 yield 的地方, with 语句中的嵌套块会被执行.语句块执行结束后,生成器重新开始。如果在这个块中产生一个未处理的异常,会在生成器的内部,在 yield 产生的地方,重新抛出。因此,有可以使用一个 try...except...finally 来捕获这个异常/错误 (如果有的话), 或确保进行一些清理工作。如果捕获一个异常仅仅为了记录到 log 中或执行一些动作 (而不是去完全隐藏它), 该生成器必须重新抛出这个异常。否则,该生成器的上下文管理器会告诉这个 with 语句: 这个异常已经被处理了。with 语句会立刻恢复,执行接下来的 with语句 .

contextlib.nested(mgr1[, mgr2[, ...]])

将多个上下文管理器合并到单个嵌套上下文管理器中。

This function has been deprecated in favour of the multiple manager form of the with statement.

The one advantage of this function over the multiple manager form of the with statement is that argument unpacking allows it to be used with a variable number of context managers as follows:

from contextlib import nested

with nested(*managers):
    do_something()

请注意,如果其中一个嵌套上下文管理器的__ exit __()方法指示应该禁止异常,则不会将异常信息传递给任何剩余的外部上下文管理器。类似地,如果一个嵌套管理器的__ exit __()方法引发异常,任何先前的异常状态都将丢失;新的异常将传递给任何剩余的外部上下文管理器的__ exit __()方法。一般而言,__ exit __()方法应避免引发异常,特别是不应重新引发传入异常。

This function has two major quirks that have led to it being deprecated. Firstly, as the context managers are all constructed before the function is invoked, the __new__() and __init__() methods of the inner context managers are not actually covered by the scope of the outer context managers. 这意味着,例如,使用nested()打开两个文件是一个编程错误,因为如果在打开第二个文件时抛出异常,第一个文件将不会被及时关闭。

Secondly, if the __enter__() method of one of the inner context managers raises an exception that is caught and suppressed by the __exit__() method of one of the outer context managers, this construct will raise RuntimeError rather than skipping the body of the with statement.

需要支持嵌套可变数量的上下文管理器的开发人员可以使用warnings模块来抑制此函数引发的DeprecationWarning,或者将此函数用作应用程序特定实现的模型。

Deprecated since version 2.7: The with-statement now supports this functionality directly (without the confusing error prone quirks).

contextlib.closing(thing)

返回一个上下文管理器,该上下文管理器会在语句块执行到最后,关闭 thing基本相当于:

from contextlib import contextmanager

@contextmanager
def closing(thing):
    try:
        yield thing
    finally:
        thing.close()

现在你可以这些写代码:

from contextlib import closing
import urllib

with closing(urllib.urlopen('http://www.python.org')) as page:
    for line in page:
        print line

不用显示的关闭 page即使出现一个 error, 当 with 块退出的时候, page.close() 也会被调用。

另请参阅

PEP 0343 - “with” 语句
Python with语句的说明、背景和示例。

Previous topic

27.6. warnings — Warning control

Next topic

27.8. abc — Abstract Base Classes

This Page