thkang
thkang

Reputation: 11543

staticmethod and recursion?

I have following code:

class Foo(object):
    def __init__(self):
        baz=self.bar(10)

    @staticmethod
    def bar(n):
        if n==0:
            return 'bar'
        else:
            return bar(n-1)

bar() as a recursive function it needs reference to itself. However, bar() is inside a class, and calling return bar(n-1) will not work, invoking NameError: global name 'bar' is not defined. How can I deal with this kind of situation? Should I change bar() to a class or instance method, allowing access to self or cls?

Upvotes: 31

Views: 18235

Answers (5)

Paal Pedersen
Paal Pedersen

Reputation: 1297

If the main goal is to run a recursive method, you can use plain methods for this.

I actually never saw the use for this until now. lets say you have integer thresholds you need to test, this pattern can be quite nice and easy: ( even though it can create a bit overheat, so be cautious)

class Foo(object):

    def __init__(self, n):
        self.baz = self.bar(n)

    def bar(self, n):
        if n < -10:
            return 'bar < -10'
        if n == -10:
            return 'bar -10 - -1'
        if n == 0:
            return 'bar 0 - 9'
        if n == 10:
            return 'bar 10 - 19'
        if n >= 20:
            return 'bar >= 20'
        return self.bar(n-1)

Upvotes: 0

Alphadelta14
Alphadelta14

Reputation: 2923

You can define bar() outside of Foo and then bring it in as a staticmethod so that you get all of the benefits of it being a method of the class while not having to close it or reference the class itself. I have needed something like this for class inheritance reasons.

def bar(n):
    if n==0:
        return 'bar'
    else:
        return bar(n-1)

class Foo(object):
    bar = staticmethod(bar)
    def __init__(self):
        baz=self.bar(10)

Upvotes: 6

kindall
kindall

Reputation: 184345

An alternative to using a class method or calling the class by name (as shown by others) is to use a closure to hold the reference to the function:

class Foo(object):
    def bar():
        def bar(n):
            if n == 0:
               return "bar"
            return bar(n-1)
        return bar
    bar = staticmethod(bar())

The (minor) advantage is that this is somewhat less susceptible to breaking when names change. For example, if you have a reference to Foo.bar inside bar, this relies on Foo continuing to be a global name for the class that bar is defined in. Usually this is the case but if it isn't, then the recursive call breaks.

The classmethod approach will provide the method with a reference to the class, but the class isn't otherwise needed in the method, which seems inelegant. Using the closure will also be marginally faster because it isn't doing an attribute lookup on each call.

Upvotes: 13

Martijn Pieters
Martijn Pieters

Reputation: 1124020

You can refer to bar by prefixing it with the class name:

class Foo(object):
    def __init__(self):
        baz=self.bar(10)

    @staticmethod
    def bar(n):
        if n==0:
            return 'bar'
        else:
            return Foo.bar(n-1)

Static methods are nothing but regular functions contained within the namespace of a class after all.

Alternatively, define bar as a regular function instead:

def bar(n):
    if n==0:
        return 'bar'
    else:
        return bar(n-1)

class Foo(object):
    def __init__(self):
        baz=bar(10)

which avoids the whole issue altogether.

Upvotes: 61

unddoch
unddoch

Reputation: 6004

What about that?

class Foo(object):
    def __init__(self):
        baz = self.bar(10)

    @classmethod
    def bar(cls, n):
        if n == 0:
            return 'bar'
        else:
            return cls.bar(n-1)

Upvotes: 9

Related Questions