Michele Simionato wrote:
On Sep 3, 12:19 am, Ethan Furman <et...@stoneleaf.us> wrote:
Greetings, List!
The recent thread about a recursive function in a class definition led
me back to a post about bindfunc from Arnaud, and from there I found
Michele Simionato's decorator module (many thanks! :-), and from there I
began to wonder...
from decorator import decorator
@decorator
def recursive1(func, *args, **kwargs):
return func(func, *args, **kwargs)
@recursive1
def factorial1(recurse, n):
if n < 2:
return 1
return n * recurse(n-1)
factorial(4)
TypeError: factorial1() takes exactly 2 arguments (1 given)
What are you trying to do here? I miss why you don't use the usual
definition of factorial.
If you have a real life use case which is giving you trouble please
share. I do not see
why you want to pass a function to itself (?)
M. Simionato
Factorial is an example only.
The original thread by Bearophile:
http://mail.python.org/pipermail/python-list/2009-May/711848.html
A similar thread from kj (where scopes is the actual problem):
http://mail.python.org/pipermail/python-list/2009-August/725174.html
Basic summary: the recursive decorator (the one you snipped, not the
one showing above), is a replacement for the bindfunc decorator, and
preserves the signature of the decorated function, minus the
self-referring first parameter. It solves kj's problem (although there
are arguably better ways to do so), and I think helps with Bearophiles
as well. As a bonus, the tracebacks are more accurate if the function
is called incorrectly. Consider:
In [1]: def recursive(func):
...: def wrapper(*args, **kwargs):
...: return func(wrapper, *args, **kwargs)
...: return wrapper
...:
In [2]: @recursive
...: def factorial(recurse, n):
...: if n < 2:
...: return 1
...: else:
...: return n * recurse(n-1)
...:
In [3]: factorial(1, 2) # in incorrect call
--------------------------------------------------------------------
TypeError Traceback (most recent call last)
C:\pythonlib\<ipython console> in <module>()
C:\pythonlib\<ipython console> in wrapper(*args, **kwargs)
TypeError: factorial() takes exactly 2 arguments (3 given)
^^^^^^^^^^^^^^^^^^^^^
mildly confusing /
----------------------------------------
versus the error with the new decorator:
----------------------------------------
In [2]: factorial(4, 5) # another incorrect call
--------------------------------------------------------------------
TypeError Traceback (most recent call last)
C:\pythonlib\<ipython console> in <module>()
TypeError: factorial() takes exactly 1 argument (2 given)
^^^^^^^^^^^^^^^^^^^^
This latter error matches how factorial actually should be called, both
in normal code using it, and in the function itself, calling itself.
So that's the why and wherefore. Any comments on the new decorator
itself? Here it is again:
def recursive(func):
"""
recursive is a signature modifying decorator.
Specifially, it removes the first argument, so
that calls to the decorated function act as if
it does not exist.
"""
argspec = inspect.getargspec(func)
first_arg = argspec[0][0]
newargspec = (argspec[0][1:], ) + argspec[1:]
fi = decorator.FunctionMaker(func)
old_sig = inspect.formatargspec( \
formatvalue=lambda val: "", *argspec)[1:-1]
new_sig = inspect.formatargspec( \
formatvalue=lambda val: "", *newargspec)[1:-1]
new_def = '%s(%s)' % (fi.name, new_sig)
body = 'return func(%s)' % old_sig
def wrapper(*newargspec):
return func(wrapper, *newargspec)
evaldict = {'func':func, first_arg:wrapper}
return fi.create(new_def, body, evaldict, \
doc=fi.doc, module=fi.module)
~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list