理解Python的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)
但是这个有点复杂,尤其是你需要修改局部变量时。另一个方式是使用一个只使用一次的生成器,并用for-in语句去包装代码:

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

    for thing in controlled_execution():
	do something with thing
但是在Python2.4之前yield语句是不允许放在try-finally里面的。尽管它在后来的Python 2.5中解决了这个问题,当你知道你只是想要执行它们一次时,仍然去使用一个循环结构就有点奇怪。
所以经过思考一些其它可能性后,GvR和Python开发组最终提出了一个方法,使用一个对象而不是生成器来控制一个外部代码片的行为:

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评估这个表达式,调用__enter__方法在返回的值上(也被称为"context guard"),并且赋值给任何__enter__返回给由as指定的变量。Python将执行代码本身,不管那些代码中究竟发生了什么,然后调用保卫对象的__exit__方法。

作为一个额外的奖赏,__exit__方法可以看到异常,如果有的话。并且压制它或者act on it as necessary。为了抑制异常,只需要返回一个true值即可。例如,如下的__exit__方法吞下了所有的TypeError,但是允许其他的异常通过:

def __exit__(self, type, value, traceback):
    return isinstance(value, TypeError)
在Python 2.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
这并不是很难,不是吗?

本文翻译自这篇文章




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值