Как переопределить функции родительского класса в Python? - PullRequest
12 голосов
/ 20 марта 2010

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

Ответы [ 3 ]

33 голосов
/ 20 марта 2010

Давайте рассмотрим самый простой пример:

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.

5 голосов
/ 20 марта 2010

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

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

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

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

...