Python中with上下文管理协议的作用及用法
作者:king_weng
1、简介
with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关代码统统去掉,简化try…except…finlally
的处理流程。
那我们先理解一下try…except…finally语句是干啥的。实际上,try…except语句和try…finally语句是两种语句,用于不同的场景。但是当二者结合在一起时,可以“实现稳定性和灵活性更好的设计”。
2、try… except语句
用于处理程序执行过程中的异常情况,比如语法错误、从未定义变量上取值等等,也就是一些python程序本身引发的异常、报错。而try… except语句就是为了防止一些报错影响你的程序继续运行,就用try语句把它们抓出来(捕获)。
(1)try…except的标准格式
try: ## normal block except A: ## exc A block except: ## exc other block else:
(2)程序执行流程
–>执行normal block
–>发现有A错误,执行 exc A block(即处理异常)
–>结束
如果没有A错误呢?
–>执行normal block
–>发现B错误,开始寻找匹配B的异常处理方法,发现A,跳过,发现except others(即except:),执行exc other block
–>结束
如果没有错误呢?
–>执行normal block
–>全程没有错误,跳入else 执行noError block
–>结束
(3)异常分类
except
后面还能跟表达式的! 所谓的表达式,就是错误的定义。也就是说,我们可以捕捉一些我们想要捕捉的异常。而不是什么异常都报出来。
异常分两类:
- python标准异常
- 自定义异常
(a)Python标准异常
Python标准异常包括NameError
(未声明/初始化对象,没有属性),MemoryError
内存溢出错误等错误,
详细python标准异常详见:
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |
例:
try: a = 1 / 2 print(a) print(m) # 此处抛出python标准异常 b = 1 / 0 # 此后的语句不执行 print(b) c = 2 / 1 print(c) except NameError: print("Ops!!") except ZeroDivisionError: print("Wrong math!!") except: print("Error")
输出:
3、try…finallly语句
try…finallly
语句用于无论执行过程中有没有异常,都要执行清场工作。
格式:
try: execution block ##正常执行模块 except A: exc A block ##发生A错误时执行 except B: exc B block ##发生B错误时执行 except: other block ##发生除了A,B错误以外的其他错误时执行 else: if no exception, jump to here ##没有错误时执行 finally: final block ##总是执行
tips: 注意顺序不能乱,否则会有语法错误。如果用else就必须有except,否则会有语法错误。
例:
try: a = 1 / 2 print(a) print(m) # 抛出NameError异常 b = 1 / 0 print(b) c = 2 / 1 print(c) except NameError: print("Ops!!") # 捕获到异常 except ZeroDivisionError: print("Wrong math!!") except: print("Error") else: print("No error! yeah!") finally: # 是否异常都执行该代码块 print("finally!")
输出:
4、with…as语句
(1)With语句的基本语法
with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。其中__enter__()方法在语句体(with语句包裹起来的代码块)执行之前进入运行,__exit__()方法在语句体执行完毕退出后运行。
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
With语句的基本语法格式:
with expression [as target]: with-block
expression
:是一个需要执行的表达式;target
:是一个变量或者元组,存储的是expression
表达式执行返回的结果,可选参数。
(2)with语句原理
- 上下文管理协议(Context Management Protocol):包含方法 __enter__()和__exit__(),支持该协议的对象要实现这两个方法。
- 上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__()和__exit__()方法。上下文管理器定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。通常使用with语句调用上下文管理器,也可以通过直接调用其方法来使用。
例:执行过程
with EXPR as VAR: BLOCK
(1)执行EXPR,生成上下文管理器context_manager
;
(2)获取上下文管理器的__exit()__方法,并保存起来用于之后的调用;
(3)调用上下文管理器的__enter__()方法;如果使用了as子句,则将__enter__()方法的返回值赋值给as子句中的VAR;
(4)执行BLOCK中的表达式;
(5)不管是否执行过程中是否发生了异常,执行上下文管理器的__exit__()
方法,__exit__()方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句break/continue/return,则以None作为参数调用__exit__(None, None, None);如果执行过程中出现异常,则使用sys.exc_info得到的异常信息为参数调用__exit__
(exc_type, exc_value, exc_traceback);
(6)出现异常时,如果__exit__
(type, value, traceback)返回False,则会重新抛出异常,让with之外的语句逻辑来处理异常,这也是通用做法;如果返回True,则忽略异常,不再对异常进行处理。
这个和try finally函数有什么关系呢?其实,这样的过程等价于:
try:
执行 __enter__的内容
执行 with_block.
finally:
执行 __exit__内容
例:
class Sample(object): def __init__(self): print("__init__") def __enter__(self): print("__enter__") def __exit__(self, types, values, trace): print("type:", types) print("value:", values) print("trace:", trace) def get_sample(): return Sample() if __name__ == '__main__': # get_data() with get_sample() as sample: print("Sample:", sample)
输出:
到此这篇关于Python中with上下文管理协议的作用及用法的文章就介绍到这了,更多相关Python中with用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!