今天在网上看到一段代码,其中使用了with seam:初见不解其意,遂查询资料.
代码:
1 #! /usr/bin/env python
2 #-*- coding:utf-8 -*-
3 importtime4 from random importrandom5 from threading importThread,Semaphore6
7 sema = Semaphore(3)8
9 deffoo(tid):10 with sema:11 print("{} acquire sema".format(tid))12 wt = random() * 2
13 time.sleep(wt)14 print("{} release sema".format(tid))15
16 threads =[]17
18 for i in range(5):19 t = Thread(target=foo,args=(i,))20 threads.append(t)21 t.start()22
23 for t inthreads:24 t.join()
查询 python核心编程第二版,其中有个章节,专门介绍了with语句和上下文管理.
with语句,在Python2.6正式启用,和try-except-finally 类似,with语句也是用来简化代码的.Python中,并非任意符号都可以使用with语句,with语句仅仅工作于支持上下文管理协议的对象.
with应用场景:打开文件,日志,数据库,线程资源,简单同步,数据库连接等等.
1 with context_expr [as var]: ##context_expr:上下文表达式,[]可选2 with_suite
能和with一起使用的成员列表:
1 file2 decimal.Context3 thread.LockType4 threading.Lock5 threading.RLock6 threading.Condition7 threading.Semaphore8 threading.BoundedSemaphore
最最常见的with用法:
1 with open("file","r") as f:
for line in f:2 pass
上面的代码都做了什么操作?
程序试图打开一个文本,如果一切正常,把文本对象赋值给f,然后用迭代器遍历文本中的每一行.当完成时,关闭文本.
无论在这段代码的开始,中间,还是结束时发生了异常,都会执行清理的代码,此外文件仍然被会自动的关闭.
先上一个最简单的代码:
1 classContext:2 def __init__(self,name):3 self.name =name4 def __enter__(self):5 print("Begin.__enter__")6 returnself7 def __exit__(self, exc_type, exc_val, exc_tb):8 print("End.__exit__")9 defcontext(self):10 print("This is context ...{}".format(self.name))11
12 with Context("xurui") as context: ##如果带上 as 变量,那么__enter__()方法必须得返回一个东西,要不然会报错..13 context.context()14 with Context("xurui"):15 Context("xurui").context()
演示代码:
classSample:"""##执行__enter__方法,它将完成with语句块执行前的所有准备工作,如果with xx 后面带上参数,as val,那么__enter__返回值将赋值给
val,否则,丢弃返回值"""
def __enter__(self):print("In __enter__()")return "Foo" ##返回"Foo"给as Sample中的Sample
def __exit__(self, exc_type, exc_val, exc_tb):print("In __exit__()")defget_sample():print(type(Sample()))returnSample()
with get_sample() as Sample:print("sample:{}".format(Sample))
结果:
In__enter__()
sample:Foo
In__exit__()
但这都不是with的牛逼功能,with最强的地方,还是用来处理异常...
__exit__(),有三个参数,类型(异常类),值(异常实例),和回溯(回溯对象).
演示代码:
classSample:"""##执行__enter__方法,它将完成with语句块执行前的所有准备工作,如果with xx 后面带上参数,as val,那么__enter__返回值将赋值给
val,否则,丢弃返回值"""
def __enter__(self):returnselfdef __exit__(self, exc_type, exc_val, exc_tb):print("type:{},\nvalue:{},\ntrace:{}".format(exc_type,exc_val,exc_tb))defdo_something(self):
bar= 1 /0return bar + 10with Sample() as Sample:
Sample.do_something()print("sample:{}".format(Sample))
结果:
type:,
value:division by zero,
trace:Traceback (most recent call last):
File"C:/Users/xurui/PycharmProjects/q1/2017-03-01/error.py", line 55, in Sample.do_something()
File"C:/Users/xurui/PycharmProjects/q1/2017-03-01/error.py", line 51, indo_something
bar= 1 /0
ZeroDivisionError: division by zero
1 importqueue2 importcontextlib3
4
5 @contextlib.contextmanager6 defworker_state(xxx, val):7 xxx.append(val)8 #print(xxx)
9 try:10 yield
11 finally:12 xxx.remove(val)13 #print(xxx)
14
15
16 q =queue.Queue()17 li =[]18 q.put("xurui")19 with worker_state(li, 1):20 print("before", li)21 q.get()22 print("after", li)
自定义一个open文件
1 importcontextlib2
3
4 @contextlib.contextmanager5 defMyOpen(filename, mode):6 try:7 f = open(filename, mode, encoding='utf')8 exceptException as e:9 pass
10 else:11 yield f ##f return 给 as f的f
12 finally:13 f.close()14
15
16 with MyOpen("1.py", 'r') as f:17 ret =f.readlines()18 print(ret)