Может ли кто-нибудь объяснить точное значение наличия начальных подчеркиваний перед именем объекта в Python и разницу между ними?
Кроме того, остается ли это значение одинаковым, независимо от того, является ли рассматриваемый объект переменной, функцией, методом и т. Д.?
python
oop
naming-conventions
ivanleoncz
источник
источник
Ответы:
Единственный знак подчеркивания
Имена в классе с начальным подчеркиванием просто указывают другим программистам, что атрибут или метод предназначен для использования в качестве закрытого. Однако ничего особенного с самим именем не делается.
Цитировать ПКП-8 :
Двойное подчеркивание (название искажения)
Из документов Python :
И предупреждение с той же страницы:
пример
источник
__
двойное подчеркивание как имя переменной? какa, __ = foo()
Отличные ответы до сих пор, но некоторые лакомые кусочки отсутствуют. Одно начальное подчеркивание - это не просто соглашение: если вы используете
from foobar import *
, а модульfoobar
не определяет__all__
список, имена, импортированные из модуля , не включают имена с начальным подчеркиванием. Допустим, это в основном соглашение, так как этот случай довольно неясен ;-).Соглашение о нижнем подчеркивании широко используется не только для частных имен, но и для того, что C ++ назвал бы защищенными - например, для имен методов, которые полностью предназначены для переопределения подклассами (даже тех, которые должны быть переопределены, поскольку в базовый класс они
raise NotImplementedError
! -) часто являются именами, начинающимися с символа подчеркивания, чтобы указать коду, использующему экземпляры этого класса (или подклассы), что указанные методы не предназначены для непосредственного вызова.Например, чтобы создать потокобезопасную очередь с дисциплиной очереди, отличной от FIFO, необходимо импортировать очередь, подклассы Queue.Queue и переопределить такие методы, как
_get
и_put
; «Код клиента» никогда не называет тех ( «крючок») методы, а скорее ( «организация») общественные методы , такие , какput
иget
(это известно как метод шаблона дизайна шаблона - смотри , например , здесь за интересную презентацию на основе видео моего разговора на эту тему, с добавлением краткого изложения стенограммы).Изменить: ссылки на видео в описании переговоров теперь не работает. Вы можете найти первые два видео здесь и здесь .
источник
_var_name
или использоватьvar_name
+, исключая его из__all__
?__all__
всякий раз, когда вы хотите сделать модульfrom spam import *
дружественным (в том числе в интерактивном переводчике). Таким образом, в большинстве случаев ответ - оба ._
личное . Очевидно, я говорю об аналогиях, поскольку в Python нет ничего действительно частного . Во время погружения в семантику я бы сказал , что мы можем связать_
с Явой защитой , поскольку proctected в Java с помощью «производных классов и / или в одном пакете». Замените пакет модулем, так как PEP8 уже говорит нам, что_
это не просто соглашение, когда речь идет об*
импорте, и у вас это есть. И определенно__
было бы эквивалентно приватности Java, когда речь идет об идентификаторах в классе.__foo__
Это просто соглашение, способ для системы Python использовать имена, которые не будут конфликтовать с именами пользователей._foo
Это просто соглашение, способ для программиста указать, что переменная является закрытой (что бы это ни значило в Python).__foo
Это имеет реальное значение: интерпретатор заменяет это имя_classname__foo
на способ, чтобы гарантировать, что имя не будет совпадать с аналогичным именем в другом классе.Никакая другая форма подчеркивания не имеет значения в мире Python.
В этих соглашениях нет разницы между классом, переменной, глобальным и т. Д.
источник
__foo
и на любопытство. Как это может совпадать с аналогичными именами методов с другими классами? Я имею в виду, что вы все еще должны получить к нему доступinstance.__foo()
(если он не был переименован переводчиком), верно?from module import *
не импортирует объекты с префиксом подчеркивания. Следовательно,_foo
это больше, чем просто соглашение.B
подклассов классаA
, и оба реализуютfoo()
, тоB.foo()
переопределяет.foo()
унаследованный отA
.B
Доступ к экземпляру будет возможенB.foo()
только черезsuper(B).foo()
.__dunder__
имен неявные вызовы пропускают словарь экземпляров, так что в некоторых случаях это может быть немного больше, чем просто соглашение об именах (см. Раздел поиска специальных методов в datamodel).._variable
является полуприватным и предназначен только для конвенции.__variable
часто ошибочно считается суперприватным, в то время как его реальный смысл - просто поменять имя, чтобы предотвратить случайный доступ [1].__variable__
обычно зарезервирован для встроенных методов или переменныхВы по-прежнему можете обращаться к
.__mangled
переменным, если вы отчаянно хотите. Двойное подчеркивание просто меняет или переименовывает переменную в нечто вродеinstance._className__mangled
Пример:
t._b доступен, потому что он скрыт только по соглашению
t .__ a не найден, потому что он больше не существует из-за искажения имен
Получив доступ
instance._className__variable
вместо имени только двойного подчеркивания, вы можете получить доступ к скрытому значениюисточник
Одно подчеркивание в начале:
Python не имеет реальных частных методов. Вместо этого, одно подчеркивание в начале имени метода или атрибута означает, что вы не должны обращаться к этому методу, потому что он не является частью API.
(Этот фрагмент кода был взят из исходного кода django: django / forms / forms.py). В этом коде
errors
это открытое свойство, но метод, который вызывает это свойство, _get_errors, является «частным», поэтому вы не должны обращаться к нему.Два подчеркивания в начале:
Это вызывает много путаницы. Он не должен использоваться для создания частного метода. Он должен использоваться, чтобы избежать переопределения вашего метода подклассом или случайного доступа. Давайте посмотрим на пример:
Вывод:
Теперь создайте подкласс B и выполните настройку для метода __test.
Выходной будет ....
Как мы уже видели, A.test () не вызывал методы B .__ test (), как мы могли ожидать. Но на самом деле это правильное поведение для __. Два метода с именем __test () автоматически переименовываются (искажаются) в _A__test () и _B__test (), поэтому они не переопределяются случайно. Когда вы создаете метод, начинающийся с __, это означает, что вы не хотите, чтобы кто-либо мог его переопределить, и вы намереваетесь получить к нему доступ только из его собственного класса.
Два подчеркивания в начале и в конце:
Когда мы видим такой метод
__this__
, не вызывайте его. Это метод, который Python должен вызывать, а не вы. Давайте взглянем:Всегда есть оператор или нативная функция, которая вызывает эти магические методы. Иногда это просто зацепка вызовов Python в определенных ситуациях. Например,
__init__()
вызывается при создании объекта после__new__()
вызова для создания экземпляра ...Давайте возьмем пример ...
Для получения дополнительной информации см. Руководство PEP-8 . Дополнительные магические методы смотрите в этом PDF .
источник
Иногда у вас есть то, что выглядит как кортеж с подчеркиванием, как в
В этом случае происходит то, что _ () является псевдонимом для функции локализации, которая работает с текстом, чтобы поместить его на соответствующий язык, и т. Д. В зависимости от локали. Например, Sphinx делает это, и вы найдете среди импорта
а в sphinx.locale _ () назначается псевдонимом некоторой функции локализации.
источник
Так как многие люди имеют в виду Реймонда говорить , я просто сделать его немного легче, написав , что он сказал:
Скажем, вы не держите местную ссылку
perimeter
вCircle
. Теперь производный классTire
переопределяет реализациюperimeter
, не касаясьarea
. Когда вы звонитеTire(5).area()
, теоретически его все равно следует использоватьCircle.perimeter
для вычислений, но на самом деле он используетTire.perimeter
, что не является предполагаемым поведением. Вот почему нам нужна местная ссылка в Circle.Но почему
__perimeter
вместо_perimeter
? Потому что_perimeter
все еще дает производному классу возможность переопределить:Двойное подчеркивание имеет искажение имени, поэтому существует очень малая вероятность того, что локальная ссылка в родительском классе переопределится в производном классе. таким образом « делает ваши подклассы свободными для переопределения любого одного метода, не нарушая другие ».
Если ваш класс не будет унаследован, или переопределение метода ничего не нарушает, тогда вам просто не нужно
__double_leading_underscore
.источник
Если кто-то действительно хочет сделать переменную только для чтения, IMHO, лучшим способом будет использование property () с передачей только getter. С помощью свойства () мы можем полностью контролировать данные.
Я понимаю, что OP задал немного другой вопрос, но так как я нашел другой вопрос, спрашивающий «как установить закрытые переменные», помеченные как дубликаты, я подумал добавить сюда дополнительную информацию.
источник
Согласно https://dbader.org/blog/meaning-of-underscores-in-python
источник
Отличные ответы, и все они правильные. Я привел простой пример вместе с простым определением / значением.
Смысл:
some_variable --► это публично, каждый может увидеть это.
_some_variable --► это публично, кто угодно может увидеть это, но это соглашение, указывающее частное ... предупреждение, что Python не применяет никаких мер.
__some_varaible --► Python заменяет имя переменной на _classname__some_varaible (искажение имени AKA) и уменьшает / скрывает ее видимость и больше напоминает приватную переменную.
Просто чтобы быть честным здесь Согласно документации Python
Пример:
источник
Одиночные ведущие подчеркивания - это соглашение. нет никакой разницы с точки зрения переводчика, если имена начинаются с одного подчеркивания или нет.
Двойные начальные и конечные подчеркивания используются для встроенных методов, таких как
__init__
,__bool__
и т. Д.Двойные начальные подчеркивания без конечных аналогов также являются соглашением, однако методы класса будут искажены интерпретатором. Для переменных или имен основных функций различий не существует.
источник
Ваш вопрос хорош, речь идет не только о методах. Функции и объекты в модулях обычно имеют префикс с одним подчеркиванием и могут иметь префикс с двумя.
Но, например, имена __double_underscore не искажаются в модулях. Что происходит, так это то, что имена, начинающиеся с одного (или более) подчеркивания, не импортируются, если вы импортируете все из модуля (из модуля import *), а также имена не отображаются в справке (module).
источник
Вот простой иллюстративный пример того, как свойства двойного подчеркивания могут влиять на унаследованный класс. Итак, со следующей настройкой:
если вы потом создадите дочерний экземпляр в python REPL, вы увидите ниже
Это может быть очевидным для некоторых, но застало меня врасплох в гораздо более сложной среде
источник
«Частные» переменные экземпляра, к которым нельзя получить доступ, кроме как изнутри объекта, не существуют в Python. Однако существует соглашение, которому следует большая часть кода Python: имя с префиксом подчеркивания (например, _spam) следует рассматривать как непубличную часть API (будь то функция, метод или элемент данных) , Это следует учитывать в деталях реализации и может быть изменено без предварительного уведомления.
ссылка https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
источник
Получить факты _ и __ довольно легко; другие ответы выражают их довольно хорошо. Использование намного сложнее определить.
Вот как я это вижу:
Должен использоваться для указания того, что функция не предназначена для публичного использования, как, например, API. Это и ограничение импорта заставляют его вести себя так же, как
internal
в c #.Следует использовать, чтобы избежать коллизии имен в иерархии наследования и избежать позднего связывания. Очень похоже на личное в C #.
==>
Если вы хотите указать, что что-то не для публичного использования, но оно должно действовать как
protected
использование_
. Если вы хотите указать, что что-то не для публичного использования, но оно должно действовать какprivate
использование__
.Это также цитата, которая мне очень нравится:
Но проблема в том, что, на мой взгляд, если нет среды IDE, которая предупреждает вас при переопределении методов, обнаружение ошибки может занять некоторое время, если вы случайно переопределили метод из базового класса.
источник