Подтвердить что ты не робот

Имя метода 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()
4b9b3361

Ответ 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.