Python实用程序与with语句上下文 (contextlib)


Python标准库中的contextlib模块定义了ContextManager类,其对象可以正确管理程序中的资源。Python具有与上下文管理器一起工作的with关键字。文件对象(由内置的open()函数返回)支持ContextManager API。因此,我们经常在处理文件时使用with关键字。

下面的代码块打开一个文件并在其中写入一些数据。操作完成后,文件将被关闭,否则文件描述符可能会泄漏,导致文件损坏。

f = open("file.txt","w")
f.write("hello world")
f.close()

但是,使用以下语法使用文件的上下文管理器功能执行相同的文件操作。

with open("file.txt","w") as f:
f.write("hello world")
print ("file is closed")

如上所述,文件对象实现了ContextManager。它由with关键字启用。with块包含要为文件对象处理的语句。with块结束后,文件对象将自动关闭(无需显式调用close()方法)。任何被with块处理的对象都只在块内有效,并在其结束时立即被释放。

ContextManager类有两个基本方法__enter__()和__exit__()

__enter__() − 当with块开始时将被调用。它表示程序已进入与此对象相关的运行时上下文。

__exit__() − 当with块结束时被调用。它表示程序退出与此对象相关的运行时上下文。

文件对象也拥有这两个方法,可以通过以下解释器会话确认。

>>> f = open("file.txt","w")
>>> f.__enter__()
<_io.TextIOWrapper name = 'file.txt' mode = 'w' encoding = 'cp1252'>
>>> f.write("hello world")
11
>>> f.__exit__()
>>> f.write("hello world")
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
f.write("hello world")
ValueError: I/O operation on closed file.

调用__exit__()方法时,文件将被关闭。这就是为什么在我们尝试向已关闭的文件写入一些数据后出现ValueError的原因。

下面是contextManager更通用的用法。首先,我们定义一个包含__enter__()和__exit__()方法的类,并使用with语句为其对象启用contextManager。

import contextlib
class WithExample:
   def __init__(self):
      print ("object initialized")
   def __enter__(self):
      print ("entered context")
   def __exit__(self, *args):
      print ("exited context")
with WithExample() as w:
print ('this is a contextlib example')
print ('used by with statement')
print ('end of with block')

输出显示,with块开始后,__enter__()方法立即执行。块内的语句将被处理。当块结束时,__exit__()方法将自动被调用。

object initialized
entered context
this is a contextlib example
used by with statement
exited context
end of with block

contextlib模块具有@contextmanager装饰器,借助它我们可以编写一个基于生成器的工厂函数来自动支持with语句。使用装饰器的文件对象的上下文管理如下所示:

from contextlib import contextmanager
@contextmanager
def openfile(name):
   try:
      f = open(name, 'w')
      yield f
   finally:
      f.close()
with openfile(file.txt') as f:
f.write('hello world')
print ('file is closed')

因此,ContextManager是Python的一个非常有用的特性,可以有效地管理程序中的资源。

更新于:2020年6月27日

348 次浏览

启动你的职业生涯

通过完成课程获得认证

开始学习
广告