Deferred.callback()或Deferred.errback()能否向调用者抛出异常?
有没有可能在调用 .callback()
或 .errback()
时,出现一种情况,让调用者收到异常,而这个异常不会被 deferred 捕获呢?
假设我有以下的 deferred 和回调:
from twisted.internet import defer
def bad_callback(result):
raise Exception()
def bad_errback(result):
raise Exception()
d = defer.Deferred()
d.addCallbacks(bad_callback, bad_errback)
如果我调用 d.callback(None)
,那么 d
的结果将是来自 bad_callback()
的 Exception
。如果我调用 d.errback(Exception())
,那么 d
的结果将是来自 bad_errback()
的 Exception
。但是,在这两种情况下,异常都不会抛给调用者。
我确实知道几种情况,在这些情况下调用 .callback()
或 .errback()
会抛出异常给调用者,但这些情况都是不正确使用 deferred 的情况。
显然,如果你用不正确的参数数量调用
.callback()
或.errback()
,会抛出TypeError
。如果你调用一个已经被调用过的 deferred,会抛出
AlreadyCalledError
。调用
.callback(defer.Deferred())
会抛出AssertionError
。调用
.errback()
相当于调用.errback(failure.Failure())
,如果没有活动的异常,会抛出NoCurrentExceptionError
。
我真正想问的是:我能否安全地依赖于这样的行为:只要 deferred 还没有被调用,并且结果是正确的,调用 .callback(result)
或 .errback(exception_or_failure)
不会抛出异常?
1 个回答
我运行了你的例子,并在底部加了两行:
d.callback(None)
print("OK!")
然后得到了这个输出:
Unhandled error in Deferred:
Unhandled Error
Traceback (most recent call last):
File "callbacks.py", line 11, in <module>
d.callback(None)
File ".../twisted/internet/defer.py", line 368, in callback
self._startRunCallbacks(result)
File ".../twisted/internet/defer.py", line 464, in _startRunCallbacks
self._runCallbacks()
--- <exception caught here> ---
File ".../twisted/internet/defer.py", line 551, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "callbacks.py", line 4, in bad_callback
raise Exception()
exceptions.Exception:
OK!
所以在这个特定的情况下(正如你自己所确定的),不,异常不会被重新抛出。
一般来说,有几个地方会让异常“有效地”传播出去;比如说,如果你遇到 MemoryError
,也就是内存完全用完了,可能 Deferred
的实现会尝试调用某个函数来分配一点内存,这样异常就会返回给你。
不过,这只是使用 Python 编程时的一种风险;有几种异常(比如 MemoryError
和 KeyboardInterrupt
)可能会在没有任何警告的情况下出现。如果你的整个程序没有崩溃,那么不,callback
和 errback
不会抛出异常,除非是在你提到的那些情况下。