Python里with语句的用法与技巧
本文将详细讲解Python语言中with语句的用法,以及如何让自定义的类也支持with语句;
先看一段Python读取文件的代码:
class TooBig(Exception):pass
fp = open("text.txt",'r')
data = fp.read()
fp.close()
if len(data) > 10:
raise TooBig
print(data)
这段代码如果使用with关键字,能大大提升阅读性:
class TooBig(Exception):pass
with open("text.txt",'r') as fp:
data = fp.read()
if len(data) > 10:
raise TooBig
print(data)
with是如何实现的
with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的清理操作,释放资源,比如文件使用后自动关闭、线程锁中的自动获取和释放等;
python中有两个特殊的方法构成上下文管理协议,分别是__enter__
和__exit__
;要让自定义的类支持with语句,需要定义并实现它们;
class test:
def __init__(self, name):
self.name = name
print("__init__")
def say(self):
print("hello,",self.name)
def __enter__(self):
print("__enter__")
return self #可以返回不同的对象
def __exit__(self, exc_type, exc_value, exc_tb):
print("__exit__")
if exc_tb:
print("exited with exception raised.")
else:
print("exited without exception.")
with test("iKun") as k:
k.say()
#raise Exception
程序运行结果:
__init__ __enter__ hello, iKun __exit__ exited without exception.
test类中的__enter__()
方法返回的是自身的引用,这个引用可以赋值给as
子句中的k变量(也可省略);返回值的类型可以根据实际需要设置为不同的类型,不必是上下文管理器对象本身。
线程锁的应用
with语句也尝尝用于线程锁的使用上:
import threading
lock= threading.Lock()
#lock.acquire()
#pass
#lock.release()
with lock:
pass
其他参考
更多上下文管理器的高级用法,请参考contextlib模块中的contextmanage
装饰器、nested
函数和closing
上下文管理器;
这些对象,可以对已有的生成器函数或对象进行包装,加入对上下文管理器协议的支持,避免了专门编写上下文管理器来支持with语句。