Если сомневаетесь, оставьте его "общедоступным" - я имею в виду, не добавляйте ничего, чтобы скрыть имя вашего атрибута. Если у вас есть класс с некоторым внутренним значением, не беспокойтесь об этом. Вместо того, чтобы писать:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
напишите это по умолчанию:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
Это определенно противоречивый способ ведения дел. Новички в Python просто ненавидят его, и даже некоторые старые Python-ребята презирают это значение по умолчанию - но в любом случае это значение по умолчанию, поэтому я действительно рекомендую вам следовать ему, даже если вам неудобно.
Если вы действительно хотите отправить сообщение "Не трогайте это!" для пользователей, как правило, перед переменной ставится один знак подчеркивания. Это всего лишь условность, но люди ее понимают и проявляют двойную осторожность, имея дело с такими вещами:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok but pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
Это также может быть полезно для предотвращения конфликта между именами свойств и именами атрибутов:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
А как насчет двойного подчеркивания? Что ж, магия двойного подчеркивания используется в основном для предотвращения случайной перегрузки методов и конфликтов имен с атрибутами суперклассов . Это может быть весьма полезно, если вы напишете класс, который, как ожидается, будет расширяться много раз.
Если вы хотите использовать его для других целей, вы можете, но это не является обычным и не рекомендуется.
РЕДАКТИРОВАТЬ : Почему это так? Что ж, в обычном стиле Python не делается упор на приватность - наоборот! На то есть много причин - большинство из них спорны ... Давайте посмотрим на некоторые из них.
Python имеет свойства
Сегодня в большинстве объектно-ориентированных языков используется противоположный подход: то, что не следует использовать, не должно быть видимым, поэтому атрибуты должны быть закрытыми. Теоретически это привело бы к более управляемым, менее связанным классам, потому что никто не будет безрассудно изменять значения внутри объектов.
Однако не все так просто. Например, классы Java имеют множество атрибутов и геттеров, которые просто получают значения, и сеттеры, которые просто устанавливают значения. Вам нужно, скажем, семь строк кода для объявления одного атрибута, что программист Python сказал бы, что это излишне сложно. Кроме того, на практике вы просто пишете весь этот объем кода для получения одного общедоступного поля, поскольку вы можете изменить его значение с помощью методов получения и установки.
Так зачем же следовать этой частной политике по умолчанию? Просто сделайте свои атрибуты общедоступными по умолчанию. Конечно, в Java это проблематично, потому что, если вы решите добавить некоторую валидацию к своему атрибуту, вам потребуется изменить все
person.age = age;
в вашем коде, скажем,
person.setAge(age);
setAge()
будучи:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
Таким образом, в Java (и других языках) по умолчанию в любом случае используются геттеры и сеттеры, потому что их написание может раздражать, но может сэкономить вам много времени, если вы окажетесь в ситуации, которую я описал.
Однако в Python этого делать не нужно, поскольку у Python есть свойства. Если у вас есть этот класс:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
а затем вы решаете проверить возраст, вам не нужно менять person.age = age
части вашего кода. Просто добавьте свойство (как показано ниже)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Если вы можете это сделать и по-прежнему использовать person.age = age
, зачем вам добавлять частные поля, геттеры и сеттеры?
(Также см. Python - это не Java и эту статью о вреде использования геттеров и сеттеров .)
Все равно все видно - и попытка скрыть только усложняет вашу работу
Даже в языках, где есть частные атрибуты, вы можете получить к ним доступ через какую-то библиотеку отражения / самоанализа. И люди делают это много, в рамках и для решения насущных задач. Проблема в том, что библиотеки самоанализа - это просто сложный способ сделать то, что вы могли бы делать с общедоступными атрибутами.
Поскольку Python - очень динамичный язык, добавление этого бремени к вашим классам просто контрпродуктивно.
Проблема не в том, чтобы увидеть - это необходимо увидеть
Для Pythonista инкапсуляция - это не неспособность видеть внутреннее устройство классов, а возможность не смотреть на него. Я имею в виду, что инкапсуляция - это свойство компонента, которое позволяет использовать его, не беспокоя пользователя о внутренних деталях. Если вы можете использовать компонент, не беспокоясь о его реализации, то он инкапсулирован (по мнению программиста Python).
Теперь, если вы написали свой класс таким образом, чтобы вы могли использовать его, не задумываясь о деталях реализации, нет проблем, если вы по какой-то причине захотите заглянуть внутрь класса. Дело в том, что ваш API должен быть хорошим, а остальное - детали.
Гвидо так сказал
Ну, это не противоречивым: он так сказал, на самом деле . (Ищите «открытое кимоно».)
Это культура
Да, причины есть, но нет. В основном это культурный аспект программирования на Python. Откровенно говоря, могло быть и наоборот - но это не так. Кроме того, вы можете легко спросить и наоборот: почему в некоторых языках по умолчанию используются частные атрибуты? По той же основной причине, что и в практике Python: потому что это культура этих языков, и каждый вариант имеет свои преимущества и недостатки.
Поскольку эта культура уже существует, вам рекомендуется следовать ей. В противном случае вас будут раздражать программисты Python, которые говорят вам удалить __
из кода, когда вы задаете вопрос в Stack Overflow :)