3.4.7.2 任意上下文回调
ExitStack还支持关闭上下文的任意回调,从而可以狠容易地清理不通过上下文管理器控制的资源。
import contextlib
def callback(*args,**kwds):
print('closing callback({},{})'.format(args,kwds))
with contextlib.ExitStack() as stack:
stack.callback(callback,'arg1','arg2')
stack.callback(callback,arg3='val3')
与完整上下文管理器的__exit__()方法一样,这些回调会按其注册的逆序调用。
运行结果:
closing callback((),{‘arg3’: ‘val3’})
closing callback((‘arg1’, ‘arg2’),{})
不论是否出现错误,都会调用这些回调,而且不会为它们提供是否出现错误的任何信息。其返回值将被忽略。
import contextlib
def callback(*args,**kwds):
print('closing callback({},{})'.format(args,kwds))
try:
with contextlib.ExitStack() as stack:
stack.callback(callback,'arg1','arg2')
stack.callback(callback,arg3='val3')
raise RuntimeError('throw error')
except RuntimeError as err:
print('ERROR:{}'.format(err))
由于回调不能访问错误,所以它们无法防止异常在上下文管理器栈中继续传播。
运行结果:
closing callback((),{‘arg3’: ‘val3’})
closing callback((‘arg1’, ‘arg2’),{})
ERROR:throw error
回调提供了一种便捷的方式来清晰地定义清理逻辑,而没有创建新上下文管理器类的开销。为了提高代码的可读性,这个逻辑可以被封装到一个内联函数中,callback()可以作为一个修饰符。
import contextlib
with contextlib.ExitStack() as stack:
@stack.callback
def inline_cleanup():
print('inline_cleanup()')
print('local_resource = {!r}'.format(local_resource))
local_resource = 'resource created in context'
print('within the context')
没有办法为使用callback()修饰符注册的函数指定参数。不过,如果清理回调采用内联方式定义,那么根据作用域规则,他就可以访问调用代码中定义的变量。
运行结果:
within the context
inline_cleanup()
local_resource = ‘resource created in context’