Lad enlightened us with:[color=blue]
> I use Python 2.3.
> I have heard about decorators in Python 2.4.
> What is the decorator useful for?[/color]
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
"Lad" <python@hope.cz > wrote in message
news:1147416658 .204175.193480@ i39g2000cwa.goo glegroups.com.. .[color=blue]
> I use Python 2.3.
> I have heard about decorators in Python 2.4.
> What is the decorator useful for?
> Thanks for reply
> L.
>[/color]
Check out these examples on the Python wiki:
Lad wrote:[color=blue]
> I use Python 2.3.
> I have heard about decorators in Python 2.4.[/color]
What Python 2.4 adds is only syntactic sugar for decorators. You can do
the same - somewhat more explicitely - in 2.3.
[color=blue]
> What is the decorator useful for?[/color]
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 responsabilitie s (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
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 'onurb@xiludom. gro'.split('@')])"
"bruno at modulix" schrieb[color=blue]
>
> What Python 2.4 adds is only syntactic sugar for decorators.
> You can do the same - somewhat more explicitely - in 2.3.
>[color=green]
> > What is the decorator useful for?[/color]
>
>
> 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))[/color]
return res
^^^^^^^^^^
Shouldn't here be a return res, so that wrapper
behaves like the original function?
[color=blue]
> return _wrapper
>
> # python < 2.4
> def somefunc():
> print "in somefunc"
> return 42
>
> somefunc = deco(somefunc)
>[/color]
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 Blume enlightened us with:[color=blue]
> 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)?[/color]
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
Martin Blume wrote:[color=blue]
> "bruno at modulix" schrieb
>[/color]
(snip)[color=blue][color=green]
>>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))[/color]
>
> return res
> ^^^^^^^^^^
> Shouldn't here be a return res, so that wrapper
> behaves like the original function?[/color]
oops, my bad :(
And yes, of course.
[color=blue]
>[color=green]
>> return _wrapper
>>
>># python < 2.4
>>def somefunc():
>> print "in somefunc"
>> return 42
>>
>>somefunc = deco(somefunc)
>>[/color]
>
> Thanks for the explanation.
>
>
> Another question: Isn't decorating / wrapping usually
> done at runtime,[/color]
It is. I mean, using decorator syntax, this is done during import, which
happens at runtime.
[color=blue]
> so that the @deco notation is pretty
> useless (because you'd have to change the original
> code)?[/color]
I don't understand your question.
[color=blue]
> What do I miss here?[/color]
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 :
"Sybren Stuvel" schrieb[color=blue]
> Martin Blume enlightened us with:[/color]
Don't know if I enlightened anybody ... :-)
[color=blue][color=green]
> > 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)?[/color]
>
> Please explain why that would make the @deco
> notation pretty useless.
>[/color]
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.fu nc)
somewhere later?
"bruno at modulix" schrieb[color=blue]
>
> [snip]
>
> The use case for @decorator is for wrapping functions
> or method *in the module/class itself*.[/color]
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)?
[color=blue]
> It's not for module client code (but this of
> course doesn't prevent client code to dynamically
> add other wrappers...)
>[/color]
How do the clients it? The "oldfashion ed"
deco(doSillyWal k)
way?
Martin Blume wrote:[color=blue]
> "Sybren Stuvel" schrieb
>[color=green]
>>Martin Blume enlightened us with:[/color]
>
> Don't know if I enlightened anybody ... :-)[/color]
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.
[color=blue][color=green][color=darkred]
>>>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)?[/color]
>>
>>Please explain why that would make the @deco
>>notation pretty useless.
>>[/color]
>
> Well, if you're changing the original module,[/color]
Who's talking about "changing the original module" ?
[color=blue]
> you
> might as well insert the needed functionality in
> the original function, no?[/color]
higher order functions allow to keep orthogonal responsabilitie s
separated.
(snip)
[color=blue]
> 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?[/color]
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.
[color=blue]
> So why this @deco notation?[/color]
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_on e_hundred_locs_ func)
[color=blue]
> Can you apply it externally?[/color]
No. It doesn't make sens to replace:
mymodule.func = decorator(mymod ule.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 'onurb@xiludom. gro'.split('@')])"
"bruno at modulix" schrieb[color=blue][color=green]
> >
> > Well, if you're changing the original module,[/color]
> Who's talking about "changing the original module" ?
>[/color]
Well, you have to apply @deco in the module where
func_to_decorat ed is placed.
[color=blue]
>[color=green]
> > 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?[/color]
>
> 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.
>[/color]
Yes, that explains my confusion.
[color=blue]
>[color=green]
> > So why this @deco notation?[/color]
>
> 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)
>[/color]
That makes sense.
[color=blue]
>
> Note that all this should be clear for anyone having
> read the doc...
>[/color]
<blush>
Errm, yes, you're so right.
Thanks for reading the documentation to me
and clearing this up :-)
Martin Blume wrote:[color=blue]
> "bruno at modulix" schrieb
>[color=green]
>>[snip]
>>
>>The use case for @decorator is for wrapping functions
>>or method *in the module/class itself*.[/color]
>
> That was the question. What's the use of doing it
> like that in the module *itself*[/color]
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).
[color=blue]
> (I mean, you change
> directly the original function)?[/color]
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...
[color=blue][color=green]
>>It's not for module client code (but this of
>>course doesn't prevent client code to dynamically
>>add other wrappers...)
>>[/color]
>
> How do the clients it?[/color]
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 !-)
[color=blue]
> The "oldfashion ed"
> deco(doSillyWal k)
> way?[/color]
from monty.python import Cleese
Cleese.doSillyW alk = deco(Cleese.doS illyWalk)
HTH
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb@xiludom. gro'.split('@')])"
Comment