with/as的设计是作为常见的try/finally用法模式的替代方案。类似于try/finally语句,with/as语句也是用于定义必须执行的终止或"清理"行为。
主要用在自动关闭文件,对锁的自动上锁和开锁,也可以用类编写自己的上下文管理器
基本格式为
with expression [ as variable]:
with-block
在这里的expression要返回一个对象,如果as子句存在时,则会把对象赋值给变量variable
lock = threading.Lock()
with lock:
time.sleep(1)
上下文管理机机制保证锁会在代码块执行前获得,并且代码块执行完就释放,不管有没有发生异常
上下文管理协议
自己实现一个上下文管理协议
1、必须有__enter__和__exit__方法
2、上下文管理器的__enter__方法会被调用,如果as子句存在,其返回值会赋值给as子句中的变量,否则就会丢弃返回值
3、如果with代码块引发异常或者执行完成,__exit__方法就会被调用
#!/usr/bin/env python
class TraceBlock:
def message(self, arg):
print("running", arg)
def __enter__(self):
print("start with block")
return self
def __exit__(self, exc_type, exc_value, exc_tb):
if exc_type is None:
print("exit ok
")
else:
print("raise an exception", exc_type)
print("instance", exc_value)
return False
with TraceBlock() as action:
action.message("hello")
with TraceBlock() as action1:
action1.message("xxxxx")
raise TypeError
print("unreache")
tutu@linux-xk1e:~/Documents> ./with1.py
start with block
running hello
exit ok
start with block
running xxxxx
raise an exception <class 'TypeError'>
instance
Traceback (most recent call last):
File "./with1.py", line 21, in <module>
raise TypeError
TypeError
使用contextlib模块
contextlib中的@contextmanager装饰器能减少创建上下文管理器的代码量,不用写一个完整的类,定义enter和exit方法, 只需要实现一个yield的生成器,返回__enter__需要的值
在contextmanager装饰的生成器中,yield的作用是把函数体分成两部分,yield前面的代码在with块开始时(即调用__enter__方法)执行,yield语句后面的代码在with结束时(即调用_exit_)执行
#!/usr/bin/env python
import contextlib
@contextlib.contextmanager
def TraceBlock():
print("befgin")
yield "ABCDEFG"
print("end")
# yield返回的ABCDEFG会赋给var变量
with TraceBlock() as var:
print(var)