Python 上下文管理

有很多操作需要处理上下文;即需要在操作前打开上下文,在操作完成后清理

例如:

  • 读取文件内容,需要先获取文件句柄,读取文件,并要处理读取时的异常;最后需要关闭文件句柄
1
2
3
4
5
6
7
file = open("/tmp/foo.txt")
try:
data = file.read()
except:
raise
finally:
file.close()

with … as ..

使用 with... as.. 可以简化上下文的管理操作

1
2
with open("/tmp/foo.txt") as file:
data = file.read()

原理

with…as 的原理是处理的对象必须有 __enter()__ \ __exit()__两个方法

  • with 后的代码执行后,调用 __enter()__ 方法,将结果赋值给 as 后的变量名
  • 当 with…as.. 作用域中的代码执行完毕后,调用 __exit()__ 方法
1
2
3
4
5
6
7
8
9
10
11
class Example:
def __enter(self)__:
print("enter")
return "This is example"

def __exit__(self, type, value, trace):
print("exit")


with Example() as exp:
print(exp)

异常处理

with…as 可以处理异常,因为 __exit()__ 方法参数中的 trace 就是发生的异常,可以捕获并处理

contextlib

contextmanager

contextlib.contextmanager 是对 with…as.. 的进一步简化,是一个上下文管理类

@contextmanager 是一个装饰器,它接受一个generator,用 yield 语句把 with … as var 把变量输出出去,然后 with 语句就可以正常地工作了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from contextlib import contextlibmanager

@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()


def run_my_program():
with session_scope() as session:
ThingOne().go(session)
ThingTwo().go(session)

如果希望在某段代码执行前后自动执行特定代码,也可以用@contextmanager实现

1
2
3
4
5
6
7
8
9
@contextmanager
def tag(name):
print("<%s>" % name)
yield
print("</%s>" % name)

with tag("h1"):
print("hello")
print("world")

closing

contextlib.closing 是一个方法,closing 可以为对象添加上下文,变为上下文对象

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2017-2021 HonQi

请我喝杯咖啡吧~