Имя метода Python с двойным подчеркиванием переопределено?
Взгляните на это.
Обратите внимание, что класс B
переопределяет метод A
a()
.
In [1]: class A(object):
...: def __init__(self):
...: self.a()
...: def a(self):
...: print "A.a()"
...:
...:
In [2]: class B(A):
...: def __init__(self):
...: super(B, self).__init__()
...: def a(self):
...: print "B.a()"
...:
...:
In [3]: b = B()
B.a()
Никаких сюрпризов нет.
Теперь взглянем на это.
Обратите внимание, что метод, который теперь переопределяется, __a()
.
In [7]: class A(object):
...: def __init__(self):
...: self.__a()
...: def __a(self):
...: print "A.__a()"
...:
...:
In [8]: class B(A):
...: def __init__(self):
...: super(B, self).__init__()
...: def __a(self):
...: print "B.__a()"
...:
...:
In [9]: b = B()
A.__a()
Этот тип меня удивил.
Может кто-нибудь объяснить, почему A.__a()
вызывается вместо B.__a()
?
Что-нибудь __special__
около __a
?
Обновление:
После прочтения ответа Шона мне хотелось узнать, могу ли я переопределить метод, названный mangled, и получил этот результат:
In [11]: class B(A):
....: def __init__(self):
....: super(B, self).__init__()
....: def _A__a(self):
....: print "B._A__a()"
....:
....:
In [12]: b = B()
B._A__a()
Ответы
Ответ 1
ключевые слова с шаблоном __ * являются частными именами классов.
http://docs.python.org/reference/lexical_analysis.html#reserved-classes-of-identifiers
Цитирование:
Имена этой категории при использовании в контексте определения класса переписываются для использования искаженной формы, чтобы избежать столкновений имен между атрибутами "private" базового и производного классов
Частное имя (курсив добавлен):
Частное имя: когда идентификатор, который имеет текстовое значение в определении класса, начинается с двух или более символов подчеркивания и не заканчивается двумя или более символами подчеркивания, он считается частным именем этого класса. Частные имена преобразуются в более длинную форму до того, как для них генерируется код. Преобразование вставляет имя класса перед именем, с удалением ведущих подчеркиваний и одним подчеркиванием, вставленным перед именем класса. Например, идентификатор __spam
, входящий в класс с именем Ham, будет преобразован в _Ham__spam
. Это преобразование не зависит от синтаксического контекста, в котором используется идентификатор. Если преобразованное имя чрезвычайно длинное (длиннее 255 символов), может быть реализовано определенное усечение. Если имя класса состоит только из символов подчеркивания, преобразование не выполняется.
http://docs.python.org/reference/expressions.html#atom-identifiers
Это означает, что за кулисами B.__a()
преобразуется в нечто вроде B._B__a()
Ответ 2
In [1]: class A(object):
...: def __init__(self):
...: self.a()
...: def a(self):
...: print "A.a()"
...:
...: __str__ = a
...:
In [2]: class B(A):
...: def __init__(self):
...: super(B, self).__init__()
...: def a(self):
...: print "B.a()"
...:
...:
In [3]: b = B()
print str(b)
A.a()
Вам нужно будет объявить __str__
снова в B.