By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,422 Members | 1,336 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,422 IT Pros & Developers. It's quick & easy.

Decorator

P: n/a
Lad
I use Python 2.3.
I have heard about decorators in Python 2.4.
What is the decorator useful for?
Thanks for reply
L.

May 12 '06 #1
Share this Question
Share on Google+
13 Replies


P: n/a
Lad enlightened us with:
I use Python 2.3.
I have heard about decorators in Python 2.4.
What is the decorator useful for?


A whole lot of stuff. I've used them for:
- Logging all calls to a function, including its arguments.
- Ensuring there is a database connection before the function is
called.
- Casting the arguments to certain types before passing them to
the function.

And there is much more possible...

Sybren
--
The problem with the world is stupidity. Not saying there should be a
capital punishment for stupidity, but why don't we just take the
safety labels off of everything and let the problem solve itself?
Frank Zappa
May 12 '06 #2

P: n/a
"Lad" <py****@hope.cz> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com...
I use Python 2.3.
I have heard about decorators in Python 2.4.
What is the decorator useful for?
Thanks for reply
L.

Check out these examples on the Python wiki:
http://wiki.python.org/moin/PythonDecoratorLibrary

I've gotten to be a big fan of memoize.

-- Paul
May 12 '06 #3

P: n/a
Lad wrote:
I use Python 2.3.
I have heard about decorators in Python 2.4.
What Python 2.4 adds is only syntactic sugar for decorators. You can do
the same - somewhat more explicitely - in 2.3.
What is the decorator useful for?


FWIW, I'm not sure the name 'decorator' is such a great idea. A
decorator (read 'function decorator') is mainly a callable that takes a
callable as param and returns another callable, usually wrapping the
passed callable and adding some responsabilities (tracing, logging,
pre-post condition checks, etc). Two well-known examples are classmethod
and staticmethod.

The whole things looks like this:

def deco(func):
print "decorating %s" % func.__name__
def _wrapper(*args, **kw):
print "%s called " % func.__name__
res = func(*args, **kw)
print "%s returned %s" % (func.__name__, str(res))
return _wrapper

# python < 2.4
def somefunc():
print "in somefunc"
return 42

somefunc = deco(somefunc)

The syntactic sugar added in 2.4 allows you to avoid the explicit call
to deco():

# python >= 2.4
@deco
def someotherfunc():
return "the parrot is dead"
As you see, apart from the syntactic sugar, there's nothing new here.
It's just plain old higher order function, well known in any functional
language.

HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
May 12 '06 #4

P: n/a
"bruno at modulix" schrieb

What Python 2.4 adds is only syntactic sugar for decorators.
You can do the same - somewhat more explicitely - in 2.3.
What is the decorator useful for?

The whole things looks like this:

def deco(func):
print "decorating %s" % func.__name__
def _wrapper(*args, **kw):
print "%s called " % func.__name__
res = func(*args, **kw)
print "%s returned %s" % (func.__name__, str(res))

return res
^^^^^^^^^^
Shouldn't here be a return res, so that wrapper
behaves like the original function?
return _wrapper

# python < 2.4
def somefunc():
print "in somefunc"
return 42

somefunc = deco(somefunc)


Thanks for the explanation.
Another question: Isn't decorating / wrapping usually
done at runtime, so that the @deco notation is pretty
useless (because you'd have to change the original
code)?
What do I miss here?

Martin
May 12 '06 #5

P: n/a
Martin Blume enlightened us with:
Another question: Isn't decorating / wrapping usually done at
runtime, so that the @deco notation is pretty useless (because you'd
have to change the original code)?


Please explain why that would make the @deco notation pretty useless.

Sybren
--
The problem with the world is stupidity. Not saying there should be a
capital punishment for stupidity, but why don't we just take the
safety labels off of everything and let the problem solve itself?
Frank Zappa
May 12 '06 #6

P: n/a
Martin Blume wrote:
"bruno at modulix" schrieb
(snip)
def deco(func):
print "decorating %s" % func.__name__
def _wrapper(*args, **kw):
print "%s called " % func.__name__
res = func(*args, **kw)
print "%s returned %s" % (func.__name__, str(res))


return res
^^^^^^^^^^
Shouldn't here be a return res, so that wrapper
behaves like the original function?


oops, my bad :(
And yes, of course.
return _wrapper

# python < 2.4
def somefunc():
print "in somefunc"
return 42

somefunc = deco(somefunc)

Thanks for the explanation.
Another question: Isn't decorating / wrapping usually
done at runtime,


It is. I mean, using decorator syntax, this is done during import, which
happens at runtime.
so that the @deco notation is pretty
useless (because you'd have to change the original
code)?
I don't understand your question.
What do I miss here?


Ok, I get it (well, I think...).

The use case for @decorator is for wrapping functions or method *in the
module/class itself*. It's not for module client code (but this of
course doesn't prevent client code to dynamically add other wrappers...)

One of the primary use case makes this pretty clear IHMO : classmethod
and staticmethod :

# python < 2.4:
class Cleese(object):
def doSillyWalk(cls):
pass
doSillyWalk = classmethod(doSillyWalk)

# python >= 2.4:
class Cleese(object):
@classmethod
def doSillyWalk(cls):
pass

Another example : CherryPy uses decorators to mark methods which are
'published' (ie: are action controllers responding to a given URL)
HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
May 12 '06 #7

P: n/a
"Sybren Stuvel" schrieb
Martin Blume enlightened us with:

Don't know if I enlightened anybody ... :-)
Another question: Isn't decorating / wrapping
usually done at runtime, so that the @deco
notation is pretty useless (because you'd
have to change the original code)?


Please explain why that would make the @deco
notation pretty useless.

Well, if you're changing the original module, you
might as well insert the needed functionality in
the original function, no?
Or rename the original function, write a function
having this original name and calling from it the
original functionality?

Isn't the point of a decorator to change the
behavior externally, at runtime, possibly changing
it in different ways at different places at different
times?

So why this @deco notation? Can you apply it externally?
Meaning to
import module
first, then
@deco(module.func)
somewhere later?
Martin

May 12 '06 #8

P: n/a
"bruno at modulix" schrieb

[snip]

The use case for @decorator is for wrapping functions
or method *in the module/class itself*. That was the question. What's the use of doing it
like that in the module *itself* (I mean, you change
directly the original function)?
It's not for module client code (but this of
course doesn't prevent client code to dynamically
add other wrappers...)

How do the clients it? The "oldfashioned"
deco(doSillyWalk)
way?

Martin


May 12 '06 #9

P: n/a
Martin Blume wrote:
"Sybren Stuvel" schrieb
Martin Blume enlightened us with:
Don't know if I enlightened anybody ... :-)


Not sure...

But let's hope someone else having doubts about @decorator will find
this thread, so we won't have to point him/her to the documentation.
Another question: Isn't decorating / wrapping
usually done at runtime, so that the @deco
notation is pretty useless (because you'd
have to change the original code)?


Please explain why that would make the @deco
notation pretty useless.


Well, if you're changing the original module,


Who's talking about "changing the original module" ?
you
might as well insert the needed functionality in
the original function, no?
higher order functions allow to keep orthogonal responsabilities
separated.

(snip)
Isn't the point of a decorator to change the
behavior externally, at runtime, possibly changing
it in different ways at different places at different
times?
You're confusing the python specific @decorator syntax with the OO
design pattern by the same name. This syntax is purely syntactic sugar
for a specific use case of higher order functions.
So why this @deco notation?
To improve readability.

@decorator
def my_one_hundred_locs_func():
...

is much more readable than:
def my_one_hundred_locs_func():
...
# 100 LOCS later
my_one_hundred_locs_func = decorator(my_one_hundred_locs_func)
Can you apply it externally?


No. It doesn't make sens to replace:
mymodule.func = decorator(mymodule.myfunc)
with
@decorator
mymodule.func

Note that all this should be clear for anyone having read the doc...

HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
May 12 '06 #10

P: n/a
"bruno at modulix" schrieb

Well, if you're changing the original module, Who's talking about "changing the original module" ?

Well, you have to apply @deco in the module where
func_to_decorated is placed.
Isn't the point of a decorator to change the
behavior externally, at runtime, possibly changing
it in different ways at different places at
different times?
You're confusing the python specific @decorator
syntax with the OO design pattern by the same name.
This syntax is purely syntactic sugar
for a specific use case of higher order functions.

Yes, that explains my confusion.
So why this @deco notation?
To improve readability.

@decorator
def my_one_hundred_locs_func():
...

is much more readable than:
def my_one_hundred_locs_func():
...
# 100 LOCS later
my_one_hundred_locs_func = decorator (my_one_hundred_locs_func)

That makes sense.

Note that all this should be clear for anyone having
read the doc...

<blush>
Errm, yes, you're so right.

Thanks for reading the documentation to me
and clearing this up :-)

Martin
May 12 '06 #11

P: n/a
Martin Blume wrote:
"bruno at modulix" schrieb
[snip]

The use case for @decorator is for wrapping functions
or method *in the module/class itself*.
That was the question. What's the use of doing it
like that in the module *itself*

Readability.

Since the decoration (in the module) is somehow part of the function
definition, it's more obvious to have it expressed with a modifier-like
syntax at the top of the def statement than expressed as a function call
and rebinding after the end of def block. When reading the code, with
the @decorator syntax, the use of the decorator is pretty evident.

Once again, this is nothing more than syntactic sugar - but syntactic
sugar counts. FWIW, function decorators seems to be *much* more used
since the introduction of the @decorator syntax, when you could do the
same thing since the introduction of nested scopes and closures in
Python (dont remember the version, but this is not really new).
(I mean, you change
directly the original function)?
If you mean that the code added by the decorator could be injected
directly in the function, that's not always true (ie: classmethod and
staticmethod for example), and it just plain sucks anyway - you don't
write a decorator for a single function, you write it to separate
orthogonal concerns, like tracing, handling auth, partial application of
function, etc...
It's not for module client code (but this of
course doesn't prevent client code to dynamically
add other wrappers...)


How do the clients it?


Like it did since there are nested scopes and closures in Python. Higher
order functions are not really something new, you know - Lisp had them
way back in 1958 !-)
The "oldfashioned"
deco(doSillyWalk)
way?


from monty.python import Cleese
Cleese.doSillyWalk = deco(Cleese.doSillyWalk)

HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
May 12 '06 #12

P: n/a
"bruno at modulix" schrieb

[lucid introduction into decorators]

Thanks for the help in understanding decorators.

Martin
May 12 '06 #13

This discussion thread is closed

Replies have been disabled for this discussion.