Decorators, with optional arguments
Thomas Jollans
thomas at jollans.com
Fri Jul 2 14:55:26 EDT 2010
On 07/02/2010 07:41 PM, Stephen Hansen wrote:
> 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
Looks good! You may still want to use functools.update_wrapper or
functools.wraps on "wrap".
PS: if you weren't stuck on 2.5, but were using 3.x, there's all kinds
of fun stuff you could do with function annotations ;-)
>
> 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.
>
More information about the Python-list
mailing list