**起因:在写聊天客户端的时候线程锁不知道怎么下手,try finally 觉得太沉重,想起来 With这个环境管理器。
里面涉及Python2的,但是和python3没太大区别,仅供需要参考
**
一、With语句是什么?
- With:
- 1.上下文管理器
- 2.环境管理器
- 我们平时写程序的时候需要收尾,很典型的一个就是Open,读取文件句柄,关闭文件句柄。
例:
-
file = open("/tmp/foo.txt");data = file.read();file.close()
-
可能带来的问题:
- 可能忘记关闭文件句柄
- 文件读取数据异常
- 下面看新版本
try: f = open('xxx') except: print 'fail to open' exit(-1) try: do something except: do something finally: f.close()
- 虽然捕获异常了,但是太长了,并不符合Python语言优雅的特性。
- 下面我们的With出场:
with open("/tmp/foo.txt") as file: data = file.read()
With工作原理
- With后面的代码执行后,返回对象的__enter__()随即被调用,全部执行完毕后便调用__exit__()方法。
例:
class Sample:
def __enter__(self):
print "In __enter__()"
return "Foo"
def __exit__(self, type, value, trace):
print "In __exit__()"
def get_sample():
return Sample()
with get_sample() as sample:
print "sample:", sample
输出:
bash-3.2$ ./with_example01.py
In __enter__()
sample: Foo
In __exit__()
-
步骤:
- 1、 enter()方法被执行
- 2、enter()方法返回的值 - 这个例子中是”Foo”,赋值给变量’sample’
- 3、执行代码块,打印变量”sample”的值为 “Foo” 4. exit()方法被调用
然后With还有一个好玩的运行异常管理
- 回头看看__exit__()他又三个参数value, type 和 trace
例:
def __enter__(self):
return self
def __exit__(self, type, value, trace):
print "type:", type
print "value:", value
print "trace:", trace
def do_something(self):
bar = 1/0
return bar + 10
with Sample() as sample:
sample.do_something()
输出:
type: <type 'exceptions.ZeroDivisionError'>
value: integer division or modulo by zero
trace: <traceback object at 0x1004a8128>
Traceback (most recent call last):
File "./with_example02.py", line 19, in <module>
sample.do_something()
File "./with_example02.py", line 15, in do_something
bar = 1/0
ZeroDivisionError: integer division or modulo by zero
- 实际上,With后面的代码抛出异常后,exit()方法被执行,其中关联的异常分别传给三个参数,就抛出异常了。
- 跳过一个异常 我们可以这样做:
def __exit__(self, type, value, traceback): return isinstance(value, ZeroDivisionError)
- 除了ZeroDivisionError其他正常抛出
相关术语
- 要使用 with 语句,首先要明白上下文管理器这一概念。有了上下文管理器,with 语句才能工作。
- 下面是一组与上下文管理器和with 语句有关的概念。
- 上下文管理协议(Context Management Protocol):包含方法 enter() 和 exit(),支持该协议的对象要实现这两个方法。
- 上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__() 和 exit() 方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。
- 运行时上下文(runtime context):由上下文管理器创建,通过上下文管理器的 enter() 和__exit__() 方法实现,enter() 方法在语句体执行之前进入运行时上下文,exit() 在语句体执行完后从运行时上下文退出。with 语句支持运行时上下文这一概念。
- 上下文表达式(Context Expression):with 语句中跟在关键字 with 之后的表达式,该表达式要返回一个上下文管理器对象。
- 语句体(with-body):with 语句包裹起来的代码块,在执行语句体之前会调用上下文管理器的 enter() 方法,执行完语句体之后会执行__exit__() 方法。
梦想其实离你并不远,只是你在可以假装你没有,你不应该再拒绝自己的梦想。