[Tutor] Help with update_wrapper
Peter Otten
__peter__ at web.de
Sat Dec 10 10:56:32 CET 2011
Emeka wrote:
> Could someone explain " functools.update_wrapper" with simple examples?
Since this is not for the absolute beginner I'm assuming you are already
familiar with decorators. In their most common form these are functions that
take a function and wrap that function into another function.
@deco
def f(...):
...
is only syntactic sugar for
def f(...):
...
f = deco(f)
i. e. you can get a decorated version of f on the fly with deco(f).
Suppose you have a function add() that adds two arguments and a decorator
log_call() that prints the name of the called function before calling it:
>>> import pydoc
>>> pydoc.pager = pydoc.plainpager # this lets you see the output of help()
>>> from functools import update_wrapper
>>> def add(x, y):
... "calculate x+y"
... return x + y
...
>>> def log_call(f):
... def g(*args, **kw):
... print "calling", f.__name__
... return f(*args, **kw)
... return g
...
>>> add(1, 2)
3
>>> log_call(add)(3, 4)
calling add
7
It works, but if you want to learn more about the decorated function
>>> help(log_call(add))
Help on function g in module __main__:
g(*args, **kw)
you get the name, the signature and docstring of the wrapping function g(),
i. e. by decorating it you lose valuable information about add(). If you
decorate a mul() function
>>> @log_call
... def mul(x, y):
... "multiply x and y"
... return x * y
...
>>> help(mul)
Help on function g in module __main__:
g(*args, **kw)
the help will be exactly the same.
functools.update_wrapper() is a partial fix for the problem:
>>> add2 = update_wrapper(log_call(add), add)
>>> add2(5, 6)
calling add
11
>>> help(add2)
Help on function add in module __main__:
add(*args, **kw)
calculate x+y
It copies name and docstring (but not the function signature).
However, I don't think I will ever use it directly, I'd prefer using
functools.wraps:
>>> def log_call2(f):
... @wraps(f)
... def g(*args, **kw):
... print "calling", f.__name__
... return f(*args, **kw)
... return g
...
>>> @log_call2
... def add(x, y):
... "yadda"
... return x + y
...
>>> add(1, 2)
calling add
3
>>> help(add)
Help on function add in module __main__:
add(*args, **kw)
yadda
If you are seriously interested in this you should also have a look at
Michele Simionato's decorator module (http://pypi.python.org/pypi/decorator)
that also fixes the signature:
>>> import decorator
>>> @decorator.decorator
... def log_call(f, *args, **kw):
... print "calling", f.__name__
... return f(*args, **kw)
...
>>> @log_call
... def add(x, y):
... "calculate x+y"
... return x + y
...
>>> add(1, 2)
calling add
3
>>> help(add)
Help on function add in module __main__:
add(x, y)
calculate x+y
More information about the Tutor
mailing list