python模块之contexlib
一、上下文管理器
with是python实现上下文管理器的核心关键词。它能够在代码执行前和执行后做一些额外的事情。
最常见的代码恐怕就是文件操作了。
with open("file", "r", encoding="utf-8") as f: data = f.read()
import functools reader = functools.partial(open, mode="r", encoding="utf-8") f = reader("homework/user.txt") f.readlines()
实际上,with语句是通过__enter__和__exit__来实现的。
class Open(object): def __init__(self, file, mode, encoding="GBK"): """初始化,生成文件句柄""" self.file = file self.mode = mode self.encoding = encoding def __enter__(self): print("__enter__ has called.") try: f = open(self.file, self.mode, self.encoding) return f except Exception as e: print(e) def __exit__(self, exc_type, exc_val, exc_tb): print("__exit__ has called.") print("exc_type: ", exc_type) print("exc_val: ", exc_val) print("exc_tb: ", exc_tb) with Open("有关协议.docx", mode=\'r\', encoding="GBK") as f: data = f.readlines() """ __enter__ has called. an integer is required (got type str) # 异常提示信息 __exit__ has called. exc_type: <class \'AttributeError\'> exc_val: \'NoneType\' object has no attribute \'readlines\' exc_tb: <traceback object at 0x110ade608> """
with在开始时调用__enter__,并将结果赋给as后面的变量f。在结束时会调用__exit__,如果有异常,则会把异常类型、异常值和跟踪地址作为参数传递给__eixt__。
如果我们自己使用with,则必须在定义的类中实现__enter__和__exit__方法。
二、contextlib模块
python3内置了contextlib模块来帮助我们更加方便地实现上下文管理器。
import contextlib @contextlib.contextmanager def file_open(file_name, mode="r", encoding="utf-8"): print("file open") yield open(file_name, mode=mode, encoding=encoding) print("file end") with file_open("log.txt") as f: print("Read file.") print(f) dic = f.read() print(dic)
contextlib必须调用装饰器来装饰一个需要使用with语句的函数。在函数内部必须要使用yield将该函数变成可迭代对象。
在with时,将yield返回值赋给as后的变量。此时已执行到yield时。f包裹的内容作为do something继续执行。最后才会执行file end。