I've learned. I'll share.

November 11, 2008

Easy Python Decorators with the decorator decorator

Decorators in python are very powerful, but are often a pain to get right, especially when you want to pass arguments to the decorator. Typically, it involves defining a function in a function in a function, etc, up to 4 layers deep. Can we make it easier? What if we even made a decorator to make decorators?

Perhaps we could use it catch and log errors:

def log_error(func, *args, **kargs):
       return func(*args, **kargs)
   except Exception, error:
       print "error occurred: %r" % error

def blowup():
   raise Exception("blew up")

blowup() # this gets caught and prints the error

Or maybe we'd like to synchronize a function to make it thread-safe:

def synchronized(lock, func, *args, **kargs):
        return func(self, *args, **kargs)

missle_lock = thread.RLock()

def launch_missiles():

Or we could even use arguments to do do some object __init__ trickery (something I've had to do when working with wxpython):

def inherits_format(method, *args, **kargs):
    self, parent = args[:2]
    self.format = parent.format
    return method(*args, **kargs)

class Child:
    def __init__(self, parent):

class Parent:
    def __init__(self, format):
        self.format = format

format = object()
child  = Child(Parent(format))
assert child.format is format

If you've never worked python decorators, these are few examples of how powerful they are. But you'll probably never want to write your own because it can be a pain. If that's the case, then the decorator decorator is for you! Here's the code for it. It's a little tricky, but all you have to do is import it, slap @decorator before your decorator, make sure you call func(*args, **kargs), and you're all set. This is as easy as decorators can get.

Update: Dave left a comment and notified me that there is another, much more complete, implementation of the same idea at http://www.phyast.pitt.edu/~micheles/python/documentation.html. So, if you want a very complete module, go there. If you want something small and simple to cut and paste into your own code, use the following.

def decorator(decorator_func):
    decorator_expected_arg_count = decorator_func.func_code.co_argcount - 1
    if decorator_expected_arg_count:
        def decorator_maker(*decorator_args):
            assert len(decorator_args) == decorator_expected_arg_count, "%s expects %d args" % (decorator_func.__name__, decorator_expected_arg_count)

            def _decorator(func):
                assert callable(func), "Decorator not given a function.  Did you forget to give %r arguments?" % (decorator_func.__name__)

                def decorated_func(*args, **kargs):
                    full_args = decorator_args + (func,) + args
                    return decorator_func(*full_args, **kargs)

                decorated_func.__name__ = func.__name__
                return decorated_func
            return _decorator
        return decorator_maker
        def _decorator(func):
            def decorated_func(*args, **kargs):
                return decorator_func(func, *args, **kargs)

            decorated_func.__name__ = func.__name__
            return decorated_func
        return _decorator


  1. Hi,

    You might also want to check out Michele Simionato's decorator module. It's more heavyweight but preserves signature, docstrings, and does some other neat tricks.

  2. synchronised decorator example does not work.

  3. Dave, thanks for the heads up. I've never seen that module before, and it looks very complete and nice. It's not the first time I've written something and shared it only to find that someone else has done a better job :).

  4. ليس من السهل الحصول على شركة متميزة ومتخصصه لعملية التنظيف ومكافحة الحشرات ونقل العفش وغيرها من الخدمات فشركتنا رائده في هذا المجاال وجعل منزلك راقي وجميل حيث يتوفر لدى شركتنا عمال فلبيين وغيرهم متميزون وعلى درجه كبيره من الكفاءه والخبره كما ان شركة ركن الشروق يتوفر لديها افضل المعدات واحداثها التي تجعل الشركة متقدمه عن غيرها وجعل امور المنزل من تنظيف او مكافحة او نقل امر سهل وراقي في العمل عزيزي العميل نتمني منك الاسراع الينا وطلب الخدمة التي تريدها وسوف يصل اليك فريق على درجه كبيره من التميز والخبره والسرعه في العمل اتصل بنا ولا تتردد نصلك اينما كنت شركة تسليك مجاري بابها
    شركة مكافحة حشرات بابها
    شركة نقل عفش بابها

    شركة تنظيف خزانات بابها


Blog Archive

Google Analytics