Коли ви сумніваєтесь, залиште це "загальнодоступним" - я маю на увазі, не додайте нічого, щоб затьмарити назву вашого атрибута. Якщо у вас є клас з деяким внутрішнім значенням, не турбуйтеся про це. Замість написання:
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
А як з подвійним підкресленням? Ну, подвійна магія підкреслення використовується головним чином, щоб уникнути випадкових перевантажень методів і конфліктів імен з атрибутами суперкласів . Це може бути дуже корисно, якщо ви пишете клас, який, як очікується, буде розширений у багато разів.
Якщо ви хочете використовувати його для інших цілей, ви можете, але це ні зазвичай, ні рекомендується.
EDIT : Чому це так? Ну, звичайний стиль Python не наголошує на тому, щоб робити речі приватними - навпаки! Причин тому багато - більшість з них суперечливі ... Давайте подивимось деякі з них.
Python має властивості
Більшість мов OO сьогодні використовують протилежний підхід: те, що не слід використовувати, не повинно бути видимим, тому атрибути повинні бути приватними. Теоретично це дало б більш керовані, менш зв'язані класи, оскільки ніхто не міг би змінювати значення всередині об’єктів.
Однак це не так просто. Наприклад, у класів 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, які скажуть вам видалити __
з коду, коли ви задасте питання в переповненні стека :)