Я пытаюсь понять больше о возможностях переменных python.
На данный момент я не хочу ломать или нарушать инкапсуляцию переменных, которые объявлены как частные, т. Е. «self._variable».
Мне было интересно, не нарушит ли инкапсуляция, если дочерний класс напрямую вызывает переменную из своего родительского класса. Например:
class Parent:
def __init__():
self._randomVariable = ''
class Child(Parent):
def__init__():
super().__init__()
def doSomething():
self._randomVariable = 'Test'
Нарушает ли технически Chid.doSomething() инкапсуляцию для прямого вызова self._randomVariable в своем методе, даже если это дочерний класс?
Я не смог найти ничего, что было бы специфично для Python об инкапсуляции, а скорее вещи, основанные на Java. Это та же самая идея между Java и Python?
Можете ли вы уточнить, что означают защищенные атрибуты и в чем разница между двумя «_» и одним?
кроме того, не забывайте - все эти _ и __ являются условностью - код будет работать и без них - они просто показывают ваше намерение читателю кода
@Drako В случае _ да, это условность. Но не для __, так как python будет изменять имена для этих атрибутов и пытаться их скрыть.
@ Драко Да, я понимаю. Я подумал, что было бы хорошей практикой продолжать практиковать инкапсуляцию всякий раз, потому что, насколько я понимаю, другие языки будут вызывать ошибки.
@GhostArk Прочтите это: tutorialsteacher.com/python/…
@rdas Подойдет! Большое спасибо за ваше время и ресурсы!
@ Драко: не совсем так. _ атрибуты просто помечены как защищенные, а __ имеют свое имя искалеченный с именем класса. Поэтому, когда дочерний класс использует переменную _ от своего родителя, они имеют один и тот же атрибут, в то время как с __ они будут другими. По этой причине _ считается защищенным, а __ — частным.
true @rdas - я имел в виду, что вы часто можете видеть код без _ и __ - все еще работающий.






Инкапсуляция не так важна в Python, как в большинстве других языков (Java, C++ и т. д.), и вам действительно не следует слишком беспокоиться об этом. В сообществе Python у нас есть такой принцип, что «мы все здесь взрослые по обоюдному согласию».
Это означает, что вы несете ответственность за то, чтобы возиться с чужим кодом, но также не запрещайте другим возиться с вашим кодом, если они действительно знают, что делают. По этой причине в Python на самом деле нет private и protected, и вам не следует беспокоиться о них так же, как в Java.
Но, как теперь стало ясно, с подчеркиванием все же есть какая-то конфиденциальность. Итак, для чего они обычно используются?
self._var)Они используются для обеих частных защищенных переменных а также. Префикс вашей переменной с подчеркиванием - это (в основном) соглашение, который просто сообщает читателю, что «эта переменная используется внутри этого класса и не должна быть доступна извне». Что ж, если вашим подклассам это нужно, они все равно могут его использовать. И если вам это нужно вне класса, вы все равно можете его использовать. Но это под вашу ответственность, убедитесь, что вы ничего не сломаете.
Есть и некоторые другие незначительные эффекты, такие как from module import * отсутствие импорта переменных с префиксом подчеркивания, но соглашение о конфиденциальности является основным моментом.
self.__var)Также известные как переменные «dunder» (двойные под), они используются для искажение имени. Идея состоит в том, что если у вас есть общее имя переменной, и вы боитесь, что подклассы могут использовать одно и то же имя переменной для своих внутренних вещей, вы можете использовать префикс двойного подчеркивания, чтобы защитить вашу переменную от случайной перезаписи. Таким образом, ваш self.__var станет self._BaseClassName__var, а self.__var вашего подкласса станет self._SubClassName__var. Теперь они не будут пересекаться.
И хотя этот эффект можно использовать для имитации других языков private, я не рекомендую этого делать. Опять же, мы все здесь взрослые люди по обоюдному согласию, просто отметьте свою переменную как «частную» одним символом подчеркивания, и я не буду касаться ее, пока не буду действительно знать, что делаю.
Прежде всего, позвольте мне немного изменить вашу программу, чтобы исправить некоторые проблемы:
class Parent:
def __init__(self):
self.__randomVariable = 'Test1'
class Child(Parent):
def __init__(self):
super().__init__()
def doSomething(self):
self.__randomVariable = 'Test2'
Я добавил self к методам в качестве первых аргументов, так как это требуется при определении метода.
Я изменил назначение в родительском классе на 'Test1' вместо '' просто для примера.
Я также использовал __randomVariable с двойным подчеркиванием, так как ваш вопрос касается закрытых переменных, а для закрытых переменных требуется два подчеркивания. В Python частные переменные на самом деле не являются частными, но используется механизм «изменения имен», чтобы превратить их в переменную с именем _Parent.__randomVariable или _Child.__randomVariable в зависимости от класса, в котором они объявляются.
По поводу размаха. Если бы вы ссылались на self.__randomVariable, это относилось бы только к частной переменной с именем __randomVariable, как определено в этом классе. На самом деле в вашем случае было бы две разные такие частные переменные. Был бы один, определенный в суперклассе, который из-за механизма «искажения имен» фактически сохраняется как _Parent.__randomVariable. И есть один, определенный в подклассе, который сохраняется как _Child.__randomVariable. Итак, в вашем примере ваш дочерний класс фактически НЕ обращается к переменной из своего родительского класса; вместо этого он определяет новую приватную переменную для экземпляра дочернего класса.
Вот пример кода, чтобы проиллюстрировать, что произойдет, если вы используете приведенные выше определения:
c = Child()
print(c._Parent__randomVariable)
# prints Test1, i.e. the value assigned in the parent class
c.doSomething()
# calling doSomething will execute the assignment in the subclass
print(c._Parent__randomVariable)
# still prints Test1, i.e. the private variable in the parent class
# did not get reassigned in the method doSomething
print(c._Child__randomVariable)
# This one prints Test2, so in fact what happened is that a new
# private attribute was created in the subclass.
Следовательно, в этом фрагменте кода нет «нарушения инкапсуляции», поскольку он создает разные частные переменные экземпляра в родительском и дочернем классах. При этом частные переменные экземпляра на самом деле не «инкапсулированы», поскольку вы всегда можете получить к ним доступ (даже если вы не должны этого делать), когда вы знаете механизм искажения имен. Вот что я сделал в приведенном выше примере кода: я получил доступ к частной переменной __randomVariable родительского класса и подкласса, написав c._Parent__randomVariable соответственно c._Child__randomVariable. Это просто трюк реализации, который Python использует для имитации частных переменных.
_randomValue— это атрибутprotected. Так что нет. Если бы это было__randomValue, то это было бы.