Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 262
thkang Avatar asked Nov 01 '12 18:11

thkang


People also ask

What is a Staticmethod?

A static method (or static function) is a method defined as a member of an object but is accessible directly from an API object's constructor, rather than from an object instance created via the constructor.

When should Staticmethod be used?

staticmethods can be used when the code that belongs to a class doesn't use the object itself at all. Python doesn't have to instantiate a bound method for each object we instantiate. Bound methods are objects too, and creating them has a cost. Having a static method avoids that.

Can we use static method for recursion?

Yes, it most certainly is. When you apply static to a function, it's not the same as a static variable within a recursive function (which is a problem if it's used in the calculations).

Why do we need @staticmethod?

A static method has two main purposes: For utility or helper methods that don't require any object state. Since there is no need to access instance variables, having static methods eliminates the need for the caller to instantiate the object just to call the method.


2 Answers

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.

like image 71
Martijn Pieters Avatar answered Oct 19 '22 11:10

Martijn Pieters


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.

like image 12
kindall Avatar answered Oct 19 '22 12:10

kindall