[Tutor] Writing decorators?
Steven D'Aprano
steve at pearwood.info
Wed Jul 20 08:03:57 EDT 2016
On Wed, Jul 20, 2016 at 09:33:19AM +0200, Michael Welle wrote:
> Somewhere in this thread (or the one talking about decorators after this
> thread) it was said that a decorator 'changes a function'. I not a
> native English speaker, so it could just be a language problem. But to
> me it seems the function is replaced, not changed?
It might have been me that used the term "changes a function".
A decorator can do anything. It can replace the function with a
completely new one, ignoring the original function. It can wrap the
original function in a closure, returning the wrapper. (The wrapper then
calls the original function.) It can turn the function into a class, or
a class into a function, or return something altogether different. It
can modify the function and return it, or cause some side-effect and
then return the original function with no changes made.
For example, here is a decorator that ensures that the function has a
doc string, and inserts one if it doesn't:
def ensure_docstring(func):
if func.__doc__ is None:
func.__doc__ = "Please see the Fine Manual for '%s'" % func.__name__
return func
@ensure_docstring
def myfunc(args):
pass
In this case, the function object is actually changed, not replaced.
The most common form of decorator wraps the original function inside a
new function, as a closure, and returns the wrapper:
def decorate(func):
@functools.wraps(func)
def inner(*args):
print("inside the wrapper")
result = func(*args)
print("original returns %r" % result)
return result # can modify the result
return inner
Even though the decorator is returning a new function, the original is
still hidden deep inside that "inner" function, as part of the closure,
so in a sense, it is just a change to that original: it is *wrapped* in
another function, which does some pre-processing or post-processing, but
the original still does most of the work.
Does that help explain matters?
--
Steve
More information about the Tutor
mailing list