# recursive decorator

Ethan Furman ethan at stoneleaf.us
Thu Sep 3 18:41:05 CEST 2009

```Michele Simionato wrote:
> On Sep 3, 12:19 am, Ethan Furman <et... at 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.

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~

```