标签:结果 statement ror 管理器 文件句柄 target res 追踪 不同的
__enter__()
方法和 __exit__()
方法,在with语句中,如果用as指定了一个目标,会将 __enter__()
方法的返回值赋予这个目标。__exit__()
方法。如果__exit__()
方法返回值为true,那么这个异常将会被抑制,否则这个异常将会被重新抛出。__exit__()
方法,但是传入的参数为None, None, None。通常也是在这里放入代码进行如文件流/会话的关闭等操作。上下文管理协议(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__()
方法。
with context_expression [as target(s)]:
with-body
这里 context_expression 要返回一个上下文管理器对象,该对象并不赋值给 as 子句中的 target(s) ,如果指定了 as 子句的话,会将上下文管理器的 __enter__()
方法的返回值赋值给 target(s)。target(s) 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)。
Python 对一些内建对象进行改进,加入了对上下文管理器的支持,可以用于 with 语句中,比如可以自动关闭文件、线程锁的自动获取和释放等。假设要对一个文件进行操作,使用 with 语句可以有如下代码:
with open(r'somefileName') as somefile:
for line in somefile:
print line
# ...more code
这里使用了 with 语句,不管在处理文件过程中是否发生异常,都能保证 with 语句执行完毕后已经关闭了打开的文件句柄。如果使用传统的 try/finally 范式,则要使用类似如下代码:
somefile = open(r'somefileName')
try:
for line in somefile:
print line
# ...more code
finally:
somefile.close()
比较起来,使用 with 语句可以减少编码量。已经加入对上下文管理协议支持的还有模块 threading、decimal 等
with 语句执行过程如下:
context_manager = context_expression
exit = type(context_manager).__exit__
value = type(context_manager).__enter__(context_manager)
exc = True # True 表示正常执行,即便有异常也忽略;False 表示重新抛出异常,需要对异常进行处理
try:
try:
target = value # 如果使用了 as 子句
with-body # 执行 with-body
except:
# 执行过程中有异常发生
exc = False
# 如果 __exit__ 返回 True,则异常被忽略;如果返回 False,则重新抛出异常
# 由外层代码对异常进行处理
if not exit(context_manager, *sys.exc_info()):
raise
finally:
# 正常退出,或者通过 statement-body 中的 break/continue/return 语句退出
# 或者忽略异常退出
if exc:
exit(context_manager, None, None, None)
# 缺省返回 None,None 在布尔上下文中看做是 False
__enter__()
方法;如果使用了 as 子句,则将__enter__()
方法的返回值赋值给 as 子句中的 target(s)__exit__()
方法,
__exit__()
方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句 break/continue/return,则以 None 作为参数调用 __exit__(None, None, None)
;如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用__exit__(exc_type, exc_value, exc_traceback)
__exit__(type, value, traceback)
返回 False,则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理自定义上下文管理器
开发人员可以自定义支持上下文管理协议的类。自定义的上下文管理器要实现上下文管理协议所需要的 __enter__()
和 __exit__()
两个方法:
context_manager. __enter__()
:进入上下文管理器的运行时上下文,在语句体执行前调用。with 语句将该方法的返回值赋值给 as 子句中的 target,如果指定了 as 子句的话context_manager.__exit__(exc_type, exc_value, exc_traceback)
:退出与上下文管理器相关的运行时上下文,返回一个布尔值表示是否对发生的异常进行处理。参数表示引起退出操作的异常,如果退出时没有发生异常,则3个参数都为None。如果发生异常,返回__exit__()
失败来处理异常下面通过一个简单的示例来演示如何构建自定义的上下文管理器。注意,上下文管理器必须同时提供 ___enter__()
和 __exit__()
方法的定义,缺少任何一个都会导致 AttributeError;with 语句会先检查是否提供了 __exit__()
方法,然后检查是否定义了 ___enter__()
方法。
假设有一个资源 DummyResource,这种资源需要在访问前先分配,使用完后再释放掉;分配操作可以放到 __enter__()
方法中,释放操作可以放到 __exit__()
方法中。简单起见,这里只通过打印语句来表明当前的操作,并没有实际的资源分配与释放。
class DummyResource:
def __init__(self, tag):
self.tag = tag
print('Resource [%s]' % tag)
def __enter__(self):
print('[Enter %s]: Allocate resource.' % self.tag)
return self # 可以返回不同的对象
def __exit__(self, exc_type, exc_value, exc_tb):
print('[Exit %s]: Free resource.' % self.tag)
if exc_tb is None:
print('[Exit %s]: Exited without exception.' % self.tag)
else:
print('[Exit %s]: Exited with exception raised.' % self.tag)
return False # 可以省略,缺省的None也是被看做是False
with DummyResource('Normal'):
print('[with-body] Run without exceptions.')
DummyResource 中的 __enter__()
返回的是自身的引用,这个引用可以赋值给 as 子句中的 target 变量;返回值的类型可以根据实际需要设置为不同的类型,不必是上下文管理器对象本身。
__exit__()
方法中对变量 exc_tb 进行检测,如果不为 None,表示发生了异常,返回 False 表示需要由外部代码逻辑对异常进行处理;注意到如果没有发生异常,缺省的返回值为 None,在布尔环境中也是被看做 False,但是由于没有异常发生, __exit__()
的三个参数都为 None,上下文管理代码可以检测这种情况,做正常处理。
下面在 with 语句中访问 DummyResource :
with DummyResource('Normal'):
print('[with-body] Run without exceptions.')
with DummyResource('With-Exception'):
print('[with-body] Run with exception.')
raise Exception
第1个 with 语句的执行结果如下:
Resource [Normal]
[Enter Normal]: Allocate resource.
[with-body] Run without exceptions.
[Exit Normal]: Free resource.
[Exit Normal]: Exited without exception.
可以看到,正常执行时会先执行完语句体 with-body,然后执行 __exit__()
方法释放资源。
第2个 with 语句的执行结果如下:
Resource [With-Exception]
[Enter With-Exception]: Allocate resource.
[with-body] Run with exception.
[Exit With-Exception]: Free resource.
[Exit With-Exception]: Exited with exception raised.
Traceback (most recent call last):
File "/Users/cjw/Desktop/队列/s5.py", line 21, in <module>
raise Exception
Exception
可以看到,在抛出异常之前, __exit__
已经执行完
标签:结果 statement ror 管理器 文件句柄 target res 追踪 不同的
原文地址:https://www.cnblogs.com/cjwnb/p/11627417.html