У меня есть закрытый метод def __pickSide(self):
в родительском классе, который я хотел бы переопределить в дочернем классе. Однако дочерний класс все еще называет наследованный def __pickSide(self):
. Как я могу переопределить функцию? Имя функции дочернего класса является точно тем же как именем функции родителя.
Давайте посмотрим на самый простой пример:
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
.
Проблема, которую вы наблюдаете, заключается в том, что двойные подчеркивания искажают имя функции даже в вызовах. Это мешает полиморфизму работать правильно, поскольку имя, в которое оно преобразуется, основано на имени класса, в котором определен метод, а не на имени класса объекта, на который ссылаются. Замена двойного подчеркивания на что-то другое решит эту проблему.
Использование __ foo
names искажает имя метода, чтобы затруднить доступ к нему, когда вам это нужно. Я бы порекомендовал никогда их не использовать, потому что такие вещи, как тестирование, проходят более гладко.
В Python нет приватного, и если бы он был, это все равно помешало бы вам сделать это. (Это суть частных вещей в языках, в которых он есть.)
Согласно общепринятому соглашению, указывающему, что атрибут не является частью открытого интерфейса класса, используется одинарное начальное подчеркивание , например _foo
. Этого достаточно, чтобы сделать ваш код ясным, отделяя ваши внутренние данные от вашего общедоступного API.