Hans Hans - 4 months ago 29
Python Question

Can Python Staticmethod Call Another Local Method?

In Python, within a class, can a staticmethod call on another local function/method defined within the same class?

I tried the following code and obtained an error message saying foo1() is not defined.

class trialOne(object):

@staticmethod
def foo1():
a = 3.1
return a

@staticmethod
def foo():
a = foo1()
return a

obj = trialOne()
b = obj.foo()

Answer
class Tester:
    def local(self):
        print "I'm a local!"

    @staticmethod
    def another_stat():
        print "I'm a static!"

    @staticmethod
    def stat(inst):
        inst.local()
        Tester.another_stat()


t = Tester()
Tester.stat(t)

# Out:
# I'm a local!
# I'm a static!

Yes, you can! By definition, instance methods need an instance to associate themselves with, but as long as you have that instance, you can call local methods just as you normally would.

To go into this in a little more depth, there's nothing special about the word self. That's a variable just like any other. Any instance method of a class MUST take in an instance of that class as its first parameter, and it's convention to call that parameter self, but you could just as easily use any other name.

If it helps you understand the distinction, these two statements are semantically equivalent:

t.local()

Tester.local(t)

The first is just syntactic sugar for the second. The second is using the class name to reference a method of the Tester class, then passes in the instance as the first parameter. The first simply pretends that local is a field of t and calls it, but that call is transformed into Tester.local(t) by the Python interpreter.

Thus, calling a static method is the same syntax as Tester.local(t), except the first parameter does not have to be an instance of that class.

So classmethods and staticmethods are called in the same way, but the difference is that a class method "knows" what class it's coming from. The first parameter of a class method is always a variable that contains the class that it's being invoked from. That way if the method is inherited, it knows which method it's coming from, where a staticmethod would not know. In your comment, you said this:

@classmethod 
def stat(cls): 
    cls.another_stat()

In this example, cls is a variable that contains the class that the method is being called from, not an instance of the class that it is being called from. That is why you can call static methods with cls - because it is equivalent to Tester