0%

Python的with语句块

WITH语句块用于使用上下文管理器定义的方法。语法结构如下:

1
2
with_stmt ::=  "with" with_item ("," with_item)* ":" suite
with_item ::= expression ["as" target]

我们经常会用到文件读写:

1
2
3
f = open("a.txt", "r")
f.read()
f.close()

使用with语句块可以这么写:

1
2
with open("a.txt", "r") as f:
f.read()

也可以同时打开多个文件:

1
2
3
with open("a.txt", "r") as a, open("b.txt", "r") as b:
a.read()
b.read()

我们还可以定义自己的类使用with语句,只需要实现__enter____exit__这两个函数, 详见With Statement Context Managers

1
2
3
4
5
6
7
8
9
10
11
12
13
class A(object):
def __enter__(self):
print("----enter----")

def __exit__(self, exc_type, exc_value, traceback):
print("----exit----")

with A() as a:
print("----with----")

# >>> ----enter----
# >>> ----with----
# >>> ----exit----

除了上面那种方法之外,还可以使用contextlib.contextmanager装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from contextlib import contextmanager

@contextmanager
def managed_resource(*args, **kwds):
# Code to acquire resource, e.g.:
resource = acquire_resource(*args, **kwds)
try:
yield resource
finally:
# Code to release resource, e.g.:
release_resource(resource)

with managed_resource(timeout=3600) as resource:
pass

注意,被装饰的方法必须返回一个可迭代的对象,并且只能有一个值,这个值作为with语句块的as语句的内容, 另外,在yield之后需要释放对应的资源。所以,推荐的写法如上,被装饰的方法前半部分获取相应的资源, 然后yield出来,后半部分释放对应的资源。推荐try...except...finally...写法。