如何从取消任务取消的任务取消行为?
我梦dream以求:
task = ensure_future(foo())
def foo_done(task)
try:
return task.get_result()
except CancelError as e:
when, why = e.args
if when == "now"
# do something...
elif when == "asap":
# do something else...
else:
# do default
print(f"task cancelled because {why}")
task.add_done_callback(foo_done)
[...]
task.cancel("now", "This is an order!")
我可以在调用task.cancel()
之前将对象附加到任务上,然后检查
task = ensure_future(foo())
def foo_done(task)
try:
return task.get_result()
except CancelError as e:
when = getattr(task, "_when", "")
why = getattr(task, "_why", "")
if when == "now"
# do something...
elif when == "asap":
# do something else...
else:
# do default
print(f"task cancelled because {why}")
task.add_done_callback(foo_done)
[...]
task._when = "now"
task._why = "This is an order!"
task.cancel()
但是,在某些情况下,当我想在任务中捕获CancelError
时,它看起来很笨拙,例如:
async def foo():
# some stuff
try:
# some other stuff
except CancellError as e:
# here I have easily access to the error, but not the task :(
[...]
我正在寻找一种更多的pythonic方法。
您的解决方案以与您的例外相关的数据来装饰Task
。在任务中,您可以访问使用asyncio.Task.current_task()
处理的任务。
您还可以实现您梦dream以下装饰器(未经测试)的语法:
def propagate_when(fn):
async def wrapped(*args, **kwds):
try:
return await fn(*args, **kwds)
except CancelledError as e:
e.when = getattr(asyncio.Task.current_task(), '_when', None)
raise
return wrapped
用@propagate_when
装饰Coroutine允许foo_done
中的代码在处理CancelledError
时访问e.when
。缺点是e.when
将在任务中可用不可用 - 您仍然必须使用current_task()
。由于这种不一致,我建议坚持从任务对象阅读。
几个相关建议:
将取消代码放在存储您传递的对象的实用程序函数中,然后调用
task.cancel()
。这种薄的封装层应从当前代码中删除"笨拙"的感觉。使用前缀属性名称 - 简短且通用的属性名称(例如
_when
)可能会在将来的版本中引起冲突。(我知道这只是一个例子,但是未修复的名称总是有冲突的危险。)用一个对象对任务进行装饰,将实际数据放在其属性中。它使检索变得更简单,更清洁,并且可以选择在存储的对象上实现方法。