Как переопределить функции родительского класса в python?

У меня есть закрытый метод def __pickSide(self): в родительском классе, который я бы хотел переопределить в дочернем классе. Тем не менее, дочерний класс по-прежнему вызывает унаследованный def __pickSide(self):. Как я могу переопределить функцию? Имя функции дочернего класса точно такое же, как имя родительской функции.

Ответ 1

Посмотрите на самый простой пример:

from dis import dis

class A(object):
  def __pick(self):
      print "1"

  def doitinA(self):
      self.__pick()

class B(A):
  def __pick(self):
      print "2"

  def doitinB(self):
      self.__pick()

b = B()
b.doitinA() # prints 1
b.doitinB() # prints 2

dis(A.doitinA)
print
dis(B.doitinB)

Разборка выполняется следующим образом:

  8           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (_A__pick)
              6 CALL_FUNCTION            0
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE

 15           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (_B__pick)
              6 CALL_FUNCTION            0
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE

Как вы можете видеть, Python управляет именами функций, начинающимися с двух символов подчеркивания (и доступа к таким именам!) к имени, которое включает имя класса - в этом случае _A__pick и _B__pick). Это означает, что класс, в котором определена функция, определяет, какой из методов __pick вызывается.

Решение прост, избегайте псевдо-частных методов, удаляя двойные подчеркивания. Например, используйте _pick вместо __pick.

Ответ 2

Проблема, которую вы видите, заключается в том, что двойные подчеркивания управляют именем функции даже в вызовах. Это предотвращает правильную работу полиморфизма, так как имя, за которое оно искажено, основано на имени класса, в котором определяется метод, а не на имени класса объекта, на который ссылаются. Замена двойных подчеркиваний чем-то другим решит это.

Ответ 3

  • Использование имен __foo изменяет имя метода, чтобы сделать его более трудным для доступа к нему, когда вам нужно. Я бы порекомендовал никогда не использовать их, что делает такие вещи, как тестирование, более гладко.

  • В Python нет частного, и если бы это было так, это помешало бы вам сделать это в любом случае. (Это точка личных вещей на языках, которые у нее есть.)

  • Общее соглашение, указывающее, что атрибут не является частью общедоступного интерфейса класса, для использования одного ведущего подчеркивания, например _foo. Этого достаточно для того, чтобы ваш код четко отделял ваши внутренние данные от вашего общедоступного API.