【原创翻译,转载请注明译者及原文链接】

原文链接:

http://effbot.org/zone/python-with-statement.htm

从comp.lang.python和其他论坛来看,即使对于有经验的python程序员,Python 2.5的新with语句也让人有一些迷惑。

但实质上,一旦你理解了它所想要解决的问题,相较于python的其他内容,with表达式其实是相当简单的。看下面的代码:

    set things up
    try:
        do something
    finally:
        tear things down

在这里,“set things up”可以是打开一个文件,或者取得一些外部资源,而“tear things down”则将是关闭文件,或者释放,移除资源。try-finally的结构保证了“tear things down”这部分总会被执行,即使函数主体的代码不能正常结束。

如果你需要经常干这件事,那么把“set things up”和“tear things down”的代码放到一个库函数中并让其可以重复使用将会带来许多方便。当然你可以像这么干:

    def controlled_execution(callback):
        set things up
        try:
            callback(thing)
        finally:
            tear things down

    def my_function(thing):
        do something

    controlled_execution(my_function)

但这样有些罗嗦,尤其是当需要修改本地变量的时候。另外一种方法是使用仅一次的generator,并且使用for-in语句来“包装”代码:

    def controlled_execution():
        set things up
        try:
            yield thing
        finally:
            tear things down

    for thing in controlled_execution():
        do something with thing

但是yield在2.4及更早先的版本中甚至不允许被放到try-finally中。尽管这在2.5中被修正了,但这仍然显得有些古怪——你知道你仅仅想要执行某段语句一次,但你却使用了循环。

所以在尝试了很多方法之后,GvR和其python开发团队最终对后者进行了一个概括,使用对象而不是generator来控制外部代码的行为:

    class controlled_execution:
        def __enter__(self):
            set things up
            return thing
        def __exit__(self, type, value, traceback):
            tear things down

    with controlled_execution() as thing:
         some code

现在,当“with”语句被执行时,Python会首先计算类实例化的表达式(controlled_execution()),并基于表达式的值调用__enter__方法(这也被称为“上下文保护”,"context guard"),并且把__enter__函数的返回值赋给as后面的变量。Python随后会执行代码主体,不管主体代码发生了什么,保护(guard)对象的__exit__方法都会被调用。

作为额外的奖励,__exit__方法还可以监测异常,并且根据需要阻止异常或者对异常进行处理。要阻止异常,返回一个为true的值就可以。例如,如下的__exit_方法不会放过任何TypeError,但会让其他异常通过。

    def __exit__(self, type, value, traceback):
        return isinstance(value, TypeError)

在Python2.5中,文件对象被包装了__enter____exit__方法;前者仅仅返回文件对象本身,后者则关闭文件:

    >>> f = open("x.txt")
    >>> f
    <open file 'x.txt', mode 'r' at 0x00AE82F0>
    >>> f.__enter__()
    <open file 'x.txt', mode 'r' at 0x00AE82F0>
    >>> f.read(1)
    'X'
    >>> f.__exit__(None, None, None)
    >>> f.read(1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: I/O operation on closed file

所以,打开一个文件,对其内容进行处理,并且确认关闭文件,你可以简单地这么干:

with open("x.txt") as f:
    data = f.read()
    do something with data

这并不是很难,不是吗?

转载请注明译者及原文链接:)

posted on 2013-03-30 11:36  andy071001  阅读(334)  评论(0编辑  收藏  举报