Если сомневаетесь, оставьте его "общедоступным" - я имею в виду, не добавляйте ничего, чтобы скрыть имя вашего атрибута. Если у вас есть класс с некоторым внутренним значением, не беспокойтесь об этом. Вместо того, чтобы писать:
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 :)
Во-первых, что такое искажение имен?
Имя коверкание вызывается , когда вы находитесь в определении класса и использовании
__any_name
или__any_name_
, то есть, два (или более) ведущие подчеркивания и в большинстве один замыкающим знак подчеркивания.И сейчас:
Мнимое использование - запретить подклассам использовать атрибут, который использует класс.
Потенциальное значение состоит в том, чтобы избежать конфликтов имен с подклассами, которые хотят переопределить поведение, чтобы функциональность родительского класса продолжала работать должным образом. Однако пример в документации Python не является заменяемым Лисковым, и в голову не приходит ни одного примера, в котором я нашел бы это полезным.
Недостатком является то, что это увеличивает когнитивную нагрузку для чтения и понимания базы кода, особенно при отладке, когда вы видите двойное подчеркивание в исходном коде и искаженное имя в отладчике.
Мой личный подход - намеренно избегать этого. Я работаю с очень большой кодовой базой. Редкие случаи его использования бросаются в глаза, как больной палец, и не кажутся оправданными.
Вам нужно знать об этом, чтобы знать, когда вы это видите.
PEP 8
PEP 8 , руководство по стилю стандартной библиотеки Python, в настоящее время говорит (в сокращении):
Как это работает?
Если вы добавите два символа подчеркивания (не заканчивая двойным подчеркиванием) в определении класса, имя будет искажено, а символ подчеркивания, за которым следует имя класса, будет добавлен к объекту:
Обратите внимание, что имена будут искажены только при анализе определения класса:
Кроме того, новичкам в Python иногда сложно понять, что происходит, когда они не могут вручную получить доступ к имени, которое они видят определенным в определении класса. Это не веская причина против, но стоит подумать, если у вас обучающаяся аудитория.
Одно подчеркивание?
Когда я хочу, чтобы пользователи держали руки подальше от атрибута, я обычно использую только одно подчеркивание, но это потому, что в моей ментальной модели подклассы будут иметь доступ к имени (которое у них всегда есть, так как они могут легко определить все равно исказил имя).
Если бы я просматривал код, который использует
__
префикс, я бы спросил, почему они вызывают изменение имени, и если они не могут так же хорошо работать с одним подчеркиванием, имея в виду, что если подклассы выбирают одинаковые имена для класса и class, несмотря на это, будет конфликт имен.источник
Я бы не сказал, что практика дает лучший код. Модификаторы видимости только отвлекают вас от текущей задачи и, как побочный эффект, заставляют ваш интерфейс использоваться по назначению. Вообще говоря, обеспечение видимости не позволяет программистам все испортить, если они не прочитали документацию должным образом.
Намного лучшее решение - это путь, который поощряет Python: ваши классы и переменные должны быть хорошо документированы, а их поведение - ясным. Источник должен быть доступен. Это гораздо более расширяемый и надежный способ написания кода.
Моя стратегия в Python такова:
Прежде всего, должно быть ясно, что все делает. Задокументируйте это, если кто-то еще будет его использовать. Задокументируйте его, если хотите, чтобы он пригодился через год.
В качестве побочного примечания вам действительно следует использовать protected на этих других языках: вы никогда не знаете, что ваш класс может быть унаследован позже и для чего он может использоваться. Лучше всего защищать только те переменные, которые, как вы уверены, не могут или не должны использоваться сторонним кодом.
источник
Не следует начинать с личных данных и при необходимости делать их общедоступными. Скорее, вы должны начать с выяснения интерфейса вашего объекта. То есть вы должны начать с выяснения того, что видит мир (общедоступные материалы), а затем выяснить, какие личные вещи необходимы для этого.
Другой язык мешает сделать частным то, что когда-то было публичным. Т.е. я сломаю много кода, если сделаю свою переменную частной или защищенной. Но со свойствами в Python это не так. Скорее, я могу поддерживать тот же интерфейс даже при перестановке внутренних данных.
Разница между _ и __ в том, что python на самом деле пытается применить последнее. Конечно, особо не стараться, но усложняет. Если _ просто сообщает другим программистам, в чем заключается намерение, они могут игнорировать их на свой страх и риск. Но игнорирование этого правила иногда полезно. Примеры включают отладку, временные взломы и работу со сторонним кодом, который не предназначен для использования так, как вы его используете.
источник
На этот вопрос уже есть много хороших ответов, но я собираюсь предложить еще один. Это также частично ответ людям, которые постоянно говорят, что двойное подчеркивание не является личным (это действительно так).
Если вы посмотрите на Java / C #, у них обоих есть private / protected / public. Все это конструкции времени компиляции . Они применяются только во время компиляции. Если бы вы использовали отражение в Java / C #, вы могли бы легко получить доступ к закрытому методу.
Теперь каждый раз, когда вы вызываете функцию в Python, вы по сути используете отражение. Эти фрагменты кода одинаковы в Python.
Синтаксис «точка» - это только синтаксический сахар для последней части кода. В основном потому, что использование getattr уже некрасиво с одним вызовом функции. Дальше становится только хуже.
Так что с этим не может быть частной версии Java / C #, поскольку Python не компилирует код. Java и C # не могут проверить, является ли функция частной или общедоступной во время выполнения, поскольку эта информация исчезла (и он не знает, откуда функция вызывается).
Теперь, с этой информацией, изменение имени с помощью двойного подчеркивания имеет наибольший смысл для достижения "приватности". Теперь, когда функция вызывается из экземпляра «self» и она замечает, что начинается с «__», она просто выполняет изменение имени прямо здесь. Это просто синтаксический сахар. Этот синтаксический сахар допускает эквивалент «частного» на языке, который использует только отражение для доступа к элементам данных.
Отказ от ответственности: я никогда не слышал, чтобы кто-нибудь из разработчиков Python говорил что-либо подобное. Настоящая причина отсутствия «частного» - культурная, но вы также заметите, что большинство языков сценариев / интерпретируемых языков не имеют частного. Строгое принудительное закрытие неприменимо ни к чему, кроме времени компиляции.
источник
Во-первых: почему вы хотите скрыть свои данные? Почему это так важно?
В большинстве случаев вы действительно не хотите этого делать, но вы делаете это потому, что это делают другие.
Если вы действительно не хотите, чтобы люди что-то использовали, добавьте один знак подчеркивания перед этим. Вот и все ... Питонисты знают, что вещи с одним подчеркиванием не всегда будут работать каждый раз и могут измениться без вашего ведома.
Мы так живем, и нас это устраивает.
Использование двух подчеркиваний сделает ваш класс настолько плохим для подкласса, что даже вы не захотите работать таким образом.
источник
Выбранный ответ хорошо объясняет, как свойства устраняют необходимость в частных атрибутах , но я бы также добавил, что функции на уровне модуля устраняют необходимость в частных методах .
Если вы превратите метод в функцию на уровне модуля, вы исключите возможность для подклассов переопределить его. Перенос некоторых функций на уровень модуля более питоничен, чем попытка скрыть методы с изменением имени.
источник
Следующий фрагмент кода объяснит все разные случаи:
без подчеркивания (а)
печать всех допустимых атрибутов тестового объекта
Здесь вы можете видеть, что имя __a было изменено на _Test__a, чтобы предотвратить переопределение этой переменной каким-либо из подклассов. Эта концепция известна в Python как «искажение имен». Вы можете получить к нему доступ так:
Аналогично, в случае _a переменная предназначена только для того, чтобы уведомить разработчика о том, что ее следует использовать в качестве внутренней переменной этого класса, интерпретатор python ничего не сделает, даже если вы получите к нему доступ, но это не очень хорошая практика.
переменная может быть доступна из любого места, как переменная открытого класса.
Надеюсь, ответ вам помог :)
источник
На первый взгляд, он должен быть таким же, как и для других языков (под «другим» я имею в виду Java или C ++), но это не так.
В Java вы сделали приватными все переменные, которые не должны быть доступны снаружи. В то же время в Python этого нельзя добиться, поскольку здесь нет «приватности» (как гласит один из принципов Python - «Мы все взрослые»). Таким образом, двойное подчеркивание означает только «Ребята, не используйте это поле напрямую». То же значение имеет единственное подчеркивание, которое в то же время не вызывает головной боли при наследовании от рассматриваемого класса (всего лишь пример возможной проблемы, вызванной двойным подчеркиванием).
Итак, я бы рекомендовал вам использовать по умолчанию одинарное подчеркивание для «закрытых» членов.
источник
«Если вы сомневаетесь в том, должна ли переменная быть частной или защищенной, лучше выбрать частную». - да, в Python то же самое.
Некоторые ответы здесь говорят о «соглашениях», но не содержат ссылок на эти соглашения. В авторитетном руководстве по Python, PEP 8, прямо говорится:
Различие между общедоступным и частным, а также изменение имен в Python рассматривались в других ответах. По той же ссылке
источник
# ПРИМЕР ПРОГРАММЫ ДЛЯ изменения имени Python
источник