4

From a famous example, I learned the difference between method, classmethod and staticmethod in a Python class.

Source: What is the difference between @staticmethod and @classmethod in Python?

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x   
    # My Guesses
    def My_Question(self,x):
        self.foo(x)
        A.class_foo(x)
        A.static_foo(x)

a=A()

Now I am wondering, how to call a method, @classmethod, and @staticmethod inside the class.

I put my guesses in the My_Question function above, please correct me if I am wrong with any of these.

Nae
  • 14,209
  • 7
  • 52
  • 79
Psyduck
  • 637
  • 3
  • 10
  • 22

2 Answers2

2

Yes, your guesses will work. Note that it is also possible/normal to call staticmethods and classmethods outside the class:

class A():
    ...

A.class_foo()
A.static_foo()

Also note that inside regular instance methods, it's customary to call the staticmethods and class methods directly on the instance (self) rather than the class (A):

class A():
    def instance_method(self):
        self.class_foo()
        self.static_foo()

This allow for inheritance to work as you might expect -- If I create a B subclass from A, if I call B.instance_method(), my class_foo function will get B instead of A as the cls argument -- And possibly, if I override static_foo on B to do something slightly different than A.static_foo, this will allow the overridden version to be called as well.

Some examples might make this more clear:

class A(object):
    @staticmethod
    def static():
        print("Static, in A")

    @staticmethod
    def staticoverride():
        print("Static, in A, overrideable")

    @classmethod
    def clsmethod(cls):
        print("class, in A", cls)

    @classmethod
    def clsmethodoverrideable(cls):
        print("class, in A, overridable", cls)

    def instance_method(self):
        self.static()
        self.staticoverride()
        self.clsmethod()
        self.clsmethodoverride()

class B(A):
    @classmethod
    def clsmethodoverrideable(cls):
        print("class, in B, overridable", cls)

    @staticmethod
    def staticoverride():
        print("Static, in B, overrideable")


a = A()
b = B()
a.instance_method()
b.instance_method()

...

After you've run that, try it by changing all of the self. to A. inside instance_method. Rerun and compare. You'll see that all of the references to B have gone (even when you're calling b.instance_method()). This is why you want to use self rather than the class.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • I saw in the top answer in the referenced post saying that, a @classmethod is bounded to the class, and have to include a 'cls' just like 'self' for a normal class method. I am wondering are the 'cls' and 'self' has any actual meaning, so that we must use those 2 strings? And also why not use cls.class_foo(x) instead of self.class_foo(x)? – Psyduck Nov 03 '17 at 04:48
  • The names `self` and `cls` are _conventions_. You can use any name you want, but anyone reading your code will likely yell at you very loudly if you deviate from the normal conventions :-). In a `classmethod`, the first argument is the _class_ whereas in a normal method, the first argument is an _instance_ of the class. It's the difference between `A` and `a` in your example code. -- As to "why not use `cls.class_foo(x)`" -- You _would_ use that if you were calling one classmethod from another classmethod. In an instance method, the name `cls` isn't defined (try it with my example code). – mgilson Nov 03 '17 at 04:52
1

As @wim said, what you have is right. Here's the output when My_Question is called.

>>> a.My_Question("My_Answer=D")
executing foo(<__main__.A object at 0x0000015790FF4668>,My_Answer=D)
executing class_foo(<class '__main__.A'>,My_Answer=D)
executing static_foo(My_Answer=D)
araraonline
  • 1,502
  • 9
  • 14