Decorater inside a function? Is there a way?

Jeremy Bowers jerf at jerf.org
Fri Apr 1 16:46:14 EST 2005


On Fri, 01 Apr 2005 19:56:55 +0000, Ron_Adam wrote:

> On Fri, 01 Apr 2005 13:47:06 -0500, Jeremy Bowers <jerf at jerf.org>
> wrote:
>>Is this an April Fools gag? If so, it's not a very good one as it's quite
>>in line with the sort of question I've seen many times before. "I have
>>a hammer, how do I use it to inflate my tire?"
> 
> Not an April fools gag, I'm just new to decorators and google brings
> up lots of discussions from the past on how they may be implemented in
> the future, but not much in actually how they work or how to use them.

OK, just checking :-)

A decorator is completely equivalent in principle to

def function():
	pass
function = decorator(function)

That's a simplified form; decorators can themselves be an expression which
returns a callable that can be applied to a function and the rule for
applying several in sequence work as you'd expect (pipelining earlier
results into later ones, making for a great Obfuscated Python entry or
two based on the "function name misdirection" trick), but this simplified
form captures the essense, which is what I think you're looking for. In
particular, it's just "syntax sugar", not a "special feature".

> I'm trying to understand the use's, limits, and possibilities of
> decorators.
> 
> It just occurred to me that wrapping the contents of a function vs
> wrapping the function it's self, could be useful.

Decorators, literally, can only wrap functions. You can write a wrapper
then that does something to the arguments, which people sometimes do, but
you can't directly "wrap" the arguments. 

Note, having shown you how decorators work, you can "manually" apply the
decorator yourself:

Python 2.3.5 (#1, Mar  3 2005, 17:32:12) 
[GCC 3.4.3  (Gentoo Linux 3.4.3, ssp-3.4.3-0, pie-8.7.6.6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> string._join = string.join
>>> def joinWrap(*args, **kwargs):
...     print args, kwargs
...     return "My Wrapper", string._join(*args, **kwargs)
... 
>>> string.join = joinWrap
>>> string.join(["1","2","3"], "|")
My Wrapper (['1', '2', '3'], '|') {}
'1|2|3'
>>> 

So, whatever it is you are trying can do can still be done without the
decorator syntax, and *this* is not unheard of, though managing the
references correctly can be tricky the first few times if you're not used
to it. (Note the replaced function (join in this example) can go anywhere
the wrapper can get at it, I just stick it back in the original module for
simplicity.) It's not the first thing I reach for, in fact in all my
testing code I don't think I ever do this, but it is in the toolbox.

Do this instead of abusing the decorator syntax; you could write a
decorator that tries to figure out if it's being run in a testing
environment and conditionally affects the function, but that's probably a
bad idea.

Feeling-like-I-owed-you-an-answer-after-the-april-fool-accusation-ly yrs,
Jeremy Bowers
:-)



More information about the Python-list mailing list