69

Referring to the first answer about python's bound and unbound methods here, I have a question:

class Test:
    def method_one(self):
        print "Called method_one"
    @staticmethod
    def method_two():
        print "Called method_two"
    @staticmethod
    def method_three():
        Test.method_two()
class T2(Test):
    @staticmethod
    def method_two():
        print "T2"
a_test = Test()
a_test.method_one()
a_test.method_two()
a_test.method_three()
b_test = T2()
b_test.method_three()

produces output:

Called method_one
Called method_two
Called method_two
Called method_two

Is there a way to override a static method in python?

I expected b_test.method_three() to print "T2", but it doesn't (prints "Called method_two" instead).

Community
  • 1
  • 1
Emma
  • 52,713
  • 4
  • 19
  • 10

3 Answers3

94

In the form that you are using there, you are explicitly specifying what class's static method_two to call. If method_three was a classmethod, and you called cls.method_two, you would get the results that you wanted:

class Test:
    def method_one(self):
        print "Called method_one"
    @staticmethod
    def method_two():
        print "Called method_two"
    @classmethod
    def method_three(cls):
        cls.method_two()

class T2(Test):
    @staticmethod
    def method_two():
        print "T2"

a_test = Test()
a_test.method_one()  # -> Called method_one
a_test.method_two()  # -> Called method_two
a_test.method_three()  # -> Called method_two

b_test = T2()
b_test.method_three()  # -> T2
Test.method_two()  # -> Called method_two
T2.method_three()  # -> T2
dieend
  • 2,231
  • 1
  • 24
  • 29
lostlogic
  • 1,514
  • 12
  • 10
  • 4
    Really useful. In my case, I needed to access an instance's class. I did it like this: `instance.__class__.my_method()` – Caumons Sep 30 '14 at 12:48
3

The behavior you see is the expected behavior. Static methods are... static. When you call method_three() defined in Test it will certainly call method_two() defined by Test.

As for how to "get around" this proper behavior...

The very best way is to make methods virtual when you want virtual behavior. If you're stuck with some library code with a static method that you wish were virtual then you might look deeper to see if there's a reason or if it's just an oversight.

Otherwise, you can define a new method_three() in T2 that calls T2.method_two().

dwc
  • 24,196
  • 7
  • 44
  • 55
0

Additionally, if you want to call the "virtual static" function without an instance, you could proceed like so:

  1. Declare the function in the base class non-static like so:

    class Base:
        def my_fun(self):
            print('my_fun base')
    
    class Derived(Base):
        def my_fun(self):
            print('my_fun derived')
    
  2. Call it by passing the class type, which is not an instance, like so:

    Derived.my_fun(Derived)
    

Note, this is useful if you have a variable "class_type", which is only known during run time.

Ytsen de Boer
  • 2,797
  • 2
  • 25
  • 36
  • 1
    At that point, why not just make it a class method? Then it can be overridden and still called statically (no need to pass the class parameter). – Kurt E. Clothier Jan 29 '18 at 19:44