Python Decorators

Decorators in Python are just fantastic. Here are a few I've used in Postr. Update: the wonderful James Hensbridge expanded the decorators, so I've updated this post.

def threaded(f):
    def wrapper(*args, **kwargs):
        t = threading.Thread(target=f, args=args, kwargs=kwargs)
        t.setDaemon(True)
        t.start()
    wrapper.__name__ = f.__name__
    return wrapper

This decorator (stolen from O'Reilly) calls the method in a new thread, so execution returns straight away. I use this for long-running tasks that cannot be handled in an asynchronous manner (such as the photo uploading in Postr, which currently uses urllib). The main thread returns straight away so the interface doesn't block, and the uploads continue in the background.

Of course this new thread cannot just call GTK+ methods, as GTK+ itself isn't threadsafe. So, I have another decorator that causes a method to be always executed in the main loop by scheduling an idle handler that calls it.

def as_idle(f):
    def wrapper(*args, **kwargs):
        event = threading.Event()
        ret = []
        def task():
            ret.append(f(*args, **kwargs))
            event.set()
            return False
        gobject.idle_add(task)
        event.wait()
        return ret[0]
    wrapper.__name__ = f.__name__
    return wrapper

Erich Schubert requested return values, so James added those too. The calling function will block until the idle handler has called the decorated function. I've split the decorators out into a separate file in Postr, so you can view the latest version online.

Magic stuff!

21:30 Monday, 11 Sep 2006 [#] [computers] (8 comments)