Недавно я начал работать над собственной библиотечкой Smart PageObject для Python тестов, и заметил, что наследование аттрибутов в Python зависит от имени аттрибута, что было неожиданно для меня, хотя я пишу на этом языке уже давно (и периодически продолжаю удивляться, да).
Рассмотрим простой пример:
Здесь стоит обратить внимание на то, что аттрибут, начинающийся с двух подчеркиваний, измененяет имя - он стал называться _a__my_attr3, хотя изначально я ожидал, что он будет называться просто __my_attr3.
При наследовании этого аттрибута другим классом мы получаем сюрпризы, так как внутренние методы класса а могут обращаться к аттрибуту __my_attr3 напрямую, при этом если мы переопределяем этот метод в классе b, то мы уже не можем обращаться к этому аттрибуту, точнее можем обращаться под другим имененем.
Подберем простой пример:
Есть класс а, у которого есть метод с двойным подчеркиванием в начале имени. Мы создаем новый класс b и наследуем его от класса a. После этого мы хотим раширить функционал класса b, добавив новую функцию:
Теперь, если мы не хотим переопределять метод input, внутри класса b мы обызаны работать с аттрибутом _a__numbers вместо __numbers, и постоянно помнить об этом.
Поэтому если вы пишете код класса, который будет наследоваться и раширяться другими разработчиками, помните про то, что имена всех методов и свойств, начинающиеся с двойного подчеркивания, будут изменены. При этом внутри нашего класса а аттрибут доступен под его изначальным именем.
Редко когда действительно необходимо использовать аттрибуты с двойным подчеркиванием в начале имени, поэтому неудивительно, что поведение при наследовании для них отличается.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class a(object): | |
my_attr = 'simple attribute' | |
_my_attr2 = 'internal attribute' | |
__my_attr3 = 'real internal attribute' | |
# Magic here: ['_a__my_attr3', '_my_attr2', 'my_attr'] | |
print([name for name in dir(a) if 'my_attr' in name]) |
Здесь стоит обратить внимание на то, что аттрибут, начинающийся с двух подчеркиваний, измененяет имя - он стал называться _a__my_attr3, хотя изначально я ожидал, что он будет называться просто __my_attr3.
При наследовании этого аттрибута другим классом мы получаем сюрпризы, так как внутренние методы класса а могут обращаться к аттрибуту __my_attr3 напрямую, при этом если мы переопределяем этот метод в классе b, то мы уже не можем обращаться к этому аттрибуту, точнее можем обращаться под другим имененем.
Подберем простой пример:
Есть класс а, у которого есть метод с двойным подчеркиванием в начале имени. Мы создаем новый класс b и наследуем его от класса a. После этого мы хотим раширить функционал класса b, добавив новую функцию:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class a(object): | |
__numbers = [1, 2, 3] | |
def input(self, numbers): | |
self.__numbers = numbers | |
def sum(self): | |
print(sum(self.__numbers)) | |
class b(a): | |
def sum_x2(self): | |
print(2 * sum(self.__numbers)) # this will NOT work | |
def sum_x2_renamed(self): | |
print(2 * sum(self._a__numbers)) # this will work fine | |
my_object = b() | |
my_object.input([1, 5, 10]) | |
my_object.sum_x2_renamed() |
Теперь, если мы не хотим переопределять метод input, внутри класса b мы обызаны работать с аттрибутом _a__numbers вместо __numbers, и постоянно помнить об этом.
Поэтому если вы пишете код класса, который будет наследоваться и раширяться другими разработчиками, помните про то, что имена всех методов и свойств, начинающиеся с двойного подчеркивания, будут изменены. При этом внутри нашего класса а аттрибут доступен под его изначальным именем.
Редко когда действительно необходимо использовать аттрибуты с двойным подчеркиванием в начале имени, поэтому неудивительно, что поведение при наследовании для них отличается.