Python/上下文管理器

程序应当对获取的资源使用后释放,否则会造成资源泄露。

资源管理基础

编辑

常见办法是open()...close() 这样的函数:

f = open(filename)
# ...
f.close()

问题是如果代码块抛出了异常或者早期return,那么不会调用资源释放语句。为此,可以用try...finally语句:

f = open(filename)
try:
    # ...
finally:
    f.close()

缺点是手工释放资源有可能忘记写了,而且资源释放语句离资源获取的距离可能太远。

自动化的语句with可以处理File这样的上下文管理器类型的资源释放:

with open(filename) as f:
    # ...

实现细节

编辑

可用于with的上下文管理器类型(context manager types)必须实现__enter__(), __exit__()函数。

__init__()在创建对象时被调用,__enter__()with语句种被调用返回一个值(如对象、句柄)。

a_cm = A()
with a_cm as a:
   ...

注意事项

编辑

上下文,不是作用域

编辑

with语句不构成作用域。

生成器

编辑

生成器持续调用时,可能资源已经释放了,从而抛出异常。

with open(filename) as f:
    lines = (line.rstrip('\n') for line in f)

不是RAII

编辑

资源获取即初始化(RAII)不适用于Python这样的垃圾回收语言。因为即使对象的引用计数为0,也不一定在什么时候被垃圾回收。所以,用finally更为可靠。

参考文献

编辑