twisted.internet.defer.Deferred の使い方

Deferred を使う際の簡単な解説。Deferred を提供する際の解説ではない。

コールバックとエラーバック

Deferred はコールバックとエラーバックを同じものとして扱う。
twisted.internet.defer.Deferred._runCallbacks を参照すればすぐに分かるが、おおざっぱに言うと

try:
    result = callback(result, *args, **kwargs)
except:
    result = twisted.python.failure.Failure()
if isinstance(result, twisted.internet.defer.Deferred):
    状態を保存して result から起動されるように設定
elif isinstance(result, twisted.python.failure.Failure):
    次のエラーバック
else:
    次のコールバック

また、コールバックとエラーバックはペアで使用するものであり、ペアで登録した場合はどちらか片方しか呼ばれないことに注意されたい。
Deferred は内部で

(
    ((cb, args, kwargs, ), (eb, args, kwargs, ), )
    ...
)

上のようにコールバックとエラーバックを保持している。

最初にコールバックとエラーバックのどちらが起動するかは Deferred を提供する側が決定する。

エラー処理も同時に行いたい場合は Deferred.addBoth で failure を判別しつつ行うのが一番楽に思う。

Deferred.addCallback(cb, *args, **kwargs)

コールバックを登録する。ペアとなるエラーバックはパススルー関数である。

Deferred.addErrBack(eb, *args, **kwargs)

エラーバックを登録する。ペアとなるエラーバックはパススルー関数である。

Deferred.addBoth(callable, *args, **kwargs)

callable をコールバックとエラーバックのペアの双方に指定して登録する。

Deferred.addCallbacks(callback, errback = None, callbackArgs = None, callbackKeywords = None, errbackArgs = None, errbackKeywords = None)

コールバックとエラーバックをペアとして登録する。

Deferred.addBoth で登録した際の failure の判別

isinstance(object, twisted.python.failure.Failure)

設定済の Deferred をコピーする

copy.deepcopy でも使えばよい。