Переопределение статического метода в python

Ссылаясь на первый ответ о связанных с python и несвязанных методах здесь, у меня есть вопрос:

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()

выводит результат:

Called method_one
Called method_two
Called method_two
Called method_two

Есть ли способ переопределить статический метод в python?

Я ожидал, что b_test.method_three() напечатает "T2", но он не выполняет (вместо этого печатает "Called method_two" ).

Ответ 1

В том виде, который вы там используете, вы явно указываете, какой класс static method_two должен вызывать. Если method_three был classmethod, и вы вызвали cls.method_two, вы получили бы нужные результаты:

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

Ответ 2

Поведение, которое вы видите, - это ожидаемое поведение. Статические методы... статические. Когда вы вызываете method_three(), определенный в Test, он обязательно вызовет method_two(), определяемый Test.

Что касается того, как "обойти" это правильное поведение...

Самый лучший способ - сделать методы виртуальными, когда вы хотите виртуального поведения. Если вы застряли в некотором библиотечном коде со статическим методом, который, по вашему желанию, был виртуальным, вы могли бы глубже понять, есть ли причина или если это просто надзор.

В противном случае вы можете определить новый method_three() в T2, который вызывает T2.method_two().

Ответ 3

Кроме того, если вы хотите вызвать функцию "виртуальный статический" без экземпляра, вы можете продолжить так:

  • Объявить функцию в базовом классе нестатической, как показано ниже:

    class Base:
        def my_fun(self):
            print('my_fun base')
    
    class Derived(Base):
        def my_fun(self):
            print('my_fun derived')
    
  • Вызовите его, передав тип класса, который не является экземпляром, например:

    Derived.my_fun(Derived)
    

Обратите внимание: это полезно, если у вас есть переменная "class_type", которая известна только во время выполнения.