[Twisted-Python] addCallback0 convenience method

Drew Smathers drew.smathers at gmail.com
Mon May 4 09:59:07 MDT 2009


On Mon, May 4, 2009 at 6:26 AM, Terry Jones <terry at jon.es> wrote:
> There are two minor niggles I frequently run into when writing code with
> deferreds and callbacks:
>
>  1. I very often write callbacks that ignore the incoming result: I tend to
>    write this as def cb(_): ...
>
>  2. I sometimes write functions that I want to call both from within a
>    callback chain and when not in a callback chain. Usually this is
>    another case of writing def x(_, arg1, arg2) etc. and documenting that
>    the extra unused arg is for when the function is called as part of a
>    callback chain. This looks odder when the function is some kind of
>    utility living in different Python source file, and is thus distant
>    from its use in a callback chain.
>
> Seeing as n-1 of the add* methods of t.i.defer.Deferred are convenience
> methods for calling addCallbacks, I propose another:
>
>    def addCallback0(self, callback, *args, **kw):
>        self.addCallback(lambda result: callback(*args, **kw))
>
> This allows you to write callback functions that will not be passed the
> result of the callback chain.  That means I never have to deal with 1 and 2
> above. They're minor niggles, of course, but they make code look less
> attractive and a little harder to understand. Yes, I could write my own
> standalone function
>
>    def addCallback0(d, callback, *args, **kw):
>        d.addCallback(lambda result: callback(*args, **kw))
>
> and pass it my deferreds. And yes, I can also write my own wrapper to call
> other methods which don't take a callback result as their first argument.
>
> But all this would be nicer if addCallback0 was part of the Deferred class.
> I don't think we need a corresponding addBoth0 or addErrback0 etc., though.
>
> Terry
>

I vote instead to add a new function impartial() to standard library
functools module:

d.addCallback(impartial(callback))

Kidding, of source.  Seriously, though, I think the regular way of
attaching "lambda ign: cb(*a, **kw)" is concise enough to warrant not
adding more to the Deferred API.  A more general solution might be to
wrap functions - something like the inverse of functools.partial():

def shiftargs(level=1)
    def decorator(f)
        @wraps(f)
        def _wrapper(*a, **kw):
            return f(a[level:], **kw)
        return _wrapper
    return decorator

Still - just my opinion, of course - having such a function (either
callback0 or shiftargs) feels too esoteric, and the intent is less
explicit than the lambda statement.

-Drew




More information about the Twisted-Python mailing list