user4259083
user4259083

Reputation:

Python - can function call itself without explicitly using name?

Or a broader question: how to make a recursive function in python and, when changing its name, it only has to be changed in the declaration?

Upvotes: 9

Views: 2552

Answers (5)

Dario Colombotto
Dario Colombotto

Reputation: 191

disclaimer: dirty solution but no decorator needed

import sys

def factorial(x):
    _f = eval(sys._getframe().f_code.co_name)
    return x if x<3 else x*_f(x-1)

>>> factorial(5)
120

Upvotes: 0

dursk
dursk

Reputation: 4445

I don't know why you'd want to do this, but nonetheless, you can use a decorator to achieve this.

def recursive_function(func):
    def decorator(*args, **kwargs):
        return func(*args, my_func=func, **kwargs):
    return decorator

And then your function would look like:

@recursive_function
def my_recursive_function(my_func=None):
    ...

Upvotes: 0

user4259083
user4259083

Reputation:

I found a simple, working solution.

from functools import wraps

def recfun(f):
    @wraps(f)
    def _f(*a, **kwa): return f(_f, *a, **kwa)
    return _f

@recfun
# it's a decorator, so a separate class+method don't need to be defined
# for each function and the class does not need to be instantiated,
# as with Alex Hall's answer
def fact(self, n):
    if n > 0:
        return n * self(n-1)  # doesn't need to be self(self, n-1),
                              # as with lkraider's answer
    else:
        return 1

print(fact(10))  # works, as opposed to dursk's answer

Upvotes: 5

lkraider
lkraider

Reputation: 4181

You can bind the function to itself, so it receives a reference to itself as first parameter, just like self in a bound method:

def bind(f):
    """Decorate function `f` to pass a reference to the function
    as the first argument"""
    return f.__get__(f, type(f))

@bind
def foo(self, x):
    "This is a bound function!"
    print(self, x)

Source: https://stackoverflow.com/a/5063783/324731

Upvotes: 2

Alex Hall
Alex Hall

Reputation: 36013

Here's an (untested) idea:

class Foo(object):

    def __call__(self, *args):
        # do stuff
        self(*other_args)

Upvotes: 2

Related Questions