Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: wrapping recursive functions

How can I wrap a recursive function, recursive calls included? For example, given foo and wrap:

def foo(x):
    return foo(x - 1) if x > 0 else 1

def wrap(f):
    def wrapped(*args, **kwargs):
        print "f was called"
        return f(*args, **kwargs)

    return wrapped

wrap(foo)(x) will only output "f was called" with the first call. Recursive calls still address foo().

I don't mind monkey patching, or poking around internals. I'm not planning to add this code to the next nuclear warhead handling program, so even if it's a bad idea, I'd like to achieve the effect.

Edit: for example, would patching foo.func_globals to override foo.__name__ work? If it always does, any side-effects I should be minding?

like image 670
slezica Avatar asked May 13 '12 18:05

slezica


1 Answers

It works if you use your wrapper function as a decorator.

def wrap(f):
    def wrapped(*args, **kwargs):
        print "f was called"
        return f(*args, **kwargs)

    return wrapped

@wrap
def foo(x):
    return foo(x - 1) if x > 0 else 1

Reason being that in your example, you're only calling the result of the wrap function once. If you use it as a decorator it actually replaces the definition of foo in the module namespace with the decorated function, so its internal call resolves to the wrapped version.

like image 184
Kamil Kisiel Avatar answered Oct 06 '22 10:10

Kamil Kisiel