Decorators, with optional arguments

Stephen Hansen me+list/python at ixokai.io
Fri Jul 2 13:41:01 EDT 2010


Okay, so!

I actually never quite got around to learning to do deep and useful 
magic with decorators. I've only ever done the most basic things with 
them. Its all been a little fuzzy in my head: things like what order 
decorators end up being called in if there's more then one, etc.

But in my current situation, what I'm wanting to do is have a decorator 
that wraps a function but which takes an *optional* argument, and sets 
that argument as an attribute on said function if its there.

Here's what some tweaking and playing around has gotten me, as a recipe:

     import functools

     def my_decorator(arg):
         if callable(arg): # Stuck on 2.5. Leavemealone. :)
             protocol = None
         else:
             protocol = arg

         def wrap(fn):
             print "Wrapping."
             fn.protocol = protocol

             @functools.wraps(fn)
             def wrapper(*args, **kwargs):
                 print "Calling."
                 result = fn(*args, **kwargs)
                 print "Called."
                 return result

             return wrapper

         if not protocol: # argument-less decorator
             print "Calling wrap."
             return wrap(arg)
         else:
             print "Returning wrap."
             return wrap

To be used as:

     class Thing(object):
         @expose
         def test1(self, arg1):
             return arg1

         @expose("testing")
         def test2(self, arg2):
             return arg2

So, my question: am I doing this right? :) Some play-through testing 
appears to work. But, the dizzying array of nested def's up there leaves 
me a bit dazed, so I'm wondering if there's a simpler way to accomplish 
what I'm trying to do.

Thanks.

-- 

    ... Stephen Hansen
    ... Also: Ixokai
    ... Mail: me+list/python (AT) ixokai (DOT) io
    ... Blog: http://meh.ixokai.io/




More information about the Python-list mailing list