New tail recursion decorator
Duncan Booth
duncan.booth at invalid.invalid
Wed May 10 09:00:41 EDT 2006
Kay Schluehr wrote:
>
> Diez B. Roggisch wrote:
>> Kay Schluehr wrote:
>>
>> > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691
>>
>> Neat.
>>
>> Diez
>
> Hi Diez,
>
> for all those who already copied and pasted the original solution and
> played with it I apologize for radical changes in the latest version (
> the recipe is on version 1.5 now ! ). The latest implementation is
> again a lot faster than the previous one. It does not only get rid of
> exceptions but also of stack-frame inspection.
>
> Regards,
> Kay
>
I'm not convinced by this. You have to recognise that the function is using
tail recursion, and then you have to modify the code to know that it is
using tail recursion. This is not always trivial. For example, the given
example is:
@tail_recursion
def factorial(n, acc=1):
"calculate a factorial"
if n == 0:
return acc
res = factorial(n-1, n*acc)
return res
but a more common way to write the function would be:
@tail_recursion
def factorial(n):
"calculate a factorial"
if n == 0:
return 1
return n * factorial(n-1)
which won't work because it isn't actually tail recursion, but it looks
sufficiently close to tail recursion that it would probably mislead a lot
of people into expecting it will work. If you are going to have to rewrite
functions in a stilted manner, and they use simple tail recursion, then why
not just factor out the tail recursion in the first place.
My other problem with this is that the decorator is very fragile although
this may be fixable. e.g. (using the published example) an exception
thrown inside the function makes future calls return garbage:
>>> factorial(3)
6
>>> factorial('a')
Traceback (most recent call last):
File "<pyshell#5>", line 1, in -toplevel-
factorial('a')
File "<pyshell#1>", line 12, in result
tc = g(*args,**kwd)
File "<pyshell#3>", line 6, in factorial
res = factorial(n-1, n*acc)
TypeError: unsupported operand type(s) for -: 'str' and 'int'
>>> factorial(3)
('continue', (3,), {})
More information about the Python-list
mailing list