Что означает одиночное и двойное подчеркивание перед именем объекта?

Может ли кто-нибудь объяснить точный смысл наличия начальных подчеркиваний перед именем объекта в Python? Также объясните разницу между одинарным и двойным начальным подчеркиванием. Кроме того, остается ли это значение одинаковым, независимо от того, является ли рассматриваемый объект переменной, функцией, методом и т. Д.?

 Anton Tarasenko03 дек. 2017 г., 09:33
Отличный короткий ответ из другой ветки:stackoverflow.com/a/8689983/911945

Ответы на вопрос(14)

IMHO, лучшим способом будет использование property () с передачей только getter. С помощью свойства () мы можем получить полный контроль над данными.

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

Я понимаю, что OP задал немного другой вопрос, но так как я нашел другой вопрос, спрашивающий «как установить закрытые переменные», помеченные как дубликаты, я подумал добавить сюда дополнительную информацию.

._variable является полуприватным и предназначен только для конвенции

.__variable часто ошибочно считается суперприватным, в то время как его фактическое значение состоит в том, чтобы простопредотвратить случайный доступ[1]

.__variable__ обычно зарезервирован для встроенных методов или переменных

Вы все еще можете получить доступ.__mangled переменные, если вы отчаянно хотите. Двойное подчеркивание просто меняет или переименовывает переменную в нечто вродеinstance._className__mangled

Пример:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b доступен, потому что он скрыт только по соглашению

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t .__ a не найден, потому что он больше не существует из-за искажения имен

>>> t._Test__a
'a'

Получив доступinstance._className__variable вместо только двойного имени подчеркивания вы можете получить доступ к скрытому значению

 Vitaliy Terziev06 июл. 2017 г., 09:07
но как насчет того, если «__a» была переменной класса, то вы не можете получить к ней доступ даже с инструкциями из документации по Python ..

Одно подчеркивание в начале:

Python не имеет реальных частных методов. Вместо этого, одно подчеркивание в начале имени метода или атрибута означает, что вы не должны обращаться к этому методу, потому что он не является частью API.

class BaseForm(StrAndUnicode):

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

(Этот фрагмент кода был взят из исходного кода django: django / forms / forms.py). В этом кодеerrors является публичным свойством, но метод, который вызывает это свойство, _get_errors, является «частным», поэтому вы не должны получать к нему доступ.

Два подчеркивания в начале:

Это вызывает много путаницы. Он не должен использоваться для создания частного метода. Его следует использовать, чтобы избежать переопределения вашего метода подклассом или случайного доступа к нему. Давайте посмотрим на пример:

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

Выход:

$ python test.py
I'm test method in class A
I'm test method in class A

Теперь создайте подкласс B и выполните настройку для метода __test.

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

Выходной будет ....

$ python test.py
I'm test method in class A

Как мы уже видели, A.test () не вызывал методы B .__ test (), как мы могли ожидать. Но на самом деле это правильное поведение для __. Два метода с именем __test () автоматически переименовываются (искажаются) в _A__test () и _B__test (), поэтому они не переопределяются случайно. Когда вы создаете метод, начинающийся с __, это означает, что вы не хотите, чтобы кто-либо мог его переопределить, и вы намереваетесь получить к нему доступ только из своего собственного класса.

Два подчеркивания в начале и в конце:

Когда мы видим такой метод, как__this__не называй это. Это метод, который Python должен вызывать, а не вы. Давайте взглянем:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

Всегда есть оператор или нативная функция, которая вызывает эти магические методы. Иногда это просто ловушка Python вызывает в определенных ситуациях. Например__init__() вызывается, когда объект создается после__new__() вызывается для создания экземпляра ...

Давайте возьмем пример ...

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

Для получения более подробной информации см.Руководство по PEP-8, Дополнительные магические методы смотритеэтот PDF.

 Josiah Yoder21 авг. 2018 г., 21:30
После редактирования этого ответа я предпочитаюstackoverflow.com/a/8689983/1048186

«Частные» переменные экземпляра, к которым нельзя получить доступ, кроме как изнутри объекта, не существуют в Python. которому следует большая часть кода Python: имя с префиксом подчеркивания (например, _spam) следует рассматривать как непубличную часть API (будь то функция, метод или элемент данных) , Это следует рассматривать как деталь реализации и может быть изменено без предварительного уведомления.

ссылкаhttps://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

 Ini04 нояб. 2017 г., 01:38
_ гораздо больше похож на внутренний в c #, чем на приватный. Двойное подчеркивание гораздо более похоже на частное, чем подчеркивание на частное, я бы сказал.
Решение Вопроса
Единственный знак подчеркивания

раммистам, что атрибут или метод предназначен для использования в качестве закрытого. Однако ничего особенного с самим именем не делается.

ЦитироватьРЕР-8:

_single_leading_underscore: слабый индикатор «внутреннего использования». Например.from M import * не импортирует объекты, чье имя начинается с подчеркивания.

Двойное подчеркивание (название искажения)

Издокументы по Python:

Любой идентификатор формы__spam (по крайней мере два начальных подчеркивания, самое большее одно конечное подчеркивание) текстуально заменяется на_classname__spam, гдеclassname текущее имя класса с лидирующими символами подчеркивания. Это искажение выполняется без учета синтаксической позиции идентификатора, поэтому его можно использовать для определения переменных экземпляра класса и класса, методов, переменных, хранящихся в глобальных переменных, и даже переменных, хранящихся в экземплярах. Приватный к этому классу на экземплярах других классов.

И предупреждение с той же страницы:

Упорядочивание имен предназначено для того, чтобы дать классам простой способ определения «частных» переменных и методов экземпляра, не беспокоясь о переменных экземпляра, определенных производными классами, или перебирая переменные экземпляра кодом вне класса. Обратите внимание, что правила искажения разработаны главным образом, чтобы избежать несчастных случаев; для определенной души все еще возможно получить доступ или изменить переменную, которая считается частной.

пример
>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
 Dhruv Ramani27 июл. 2015 г., 10:10
Что если есть имя переменной, объявленное с двумя подчеркиваниями, которого нет в классе? Это просто нормальная переменная, верно?
 Ethan Furman15 июл. 2016 г., 19:48
@MarkusMeskanen: у подклассов есть свобода использовать те же имена, что и у суперкласса, без зазубрин надкласса - другими словами, имена дурда суперклассов становятся частными для себя.
 arewm05 июл. 2016 г., 17:11
@MarkusMeskanen Я не согласен с тем, что в ответе явно указывается использование дополнительного ключа для создания частных и переменных класса. В то время как dunderscore был разработан для того, чтобы эти методы и переменные были легко перезаписаны подклассами (делая их общедоступными), использование dunderscore сохраняет частный экземпляр для использования в этом классе.
 Markus Meskanen17 мая 2016 г., 12:01
Этот ответ чрезвычайно вводит в заблуждение, поскольку он заставляет читателя полагать, что dunderscore используется для того, чтобы сделать атрибуты экземпляра «суперприватными». Этоне дело, какобъяснил здесь Раймонд Хеттингер, который недвусмысленно заявляет, что dunderscore неправильно используется для обозначения членов как приватных, тогда как он был разработан, чтобы быть противоположностью приватных.
 Clayton03 дек. 2015 г., 07:24
что означает просто__ двойное подчеркивание в качестве имени переменной? любитьa, __ = foo()

с точки зрения переводчика, если имена начинаются с одного подчеркивания или нет.

Двойные начальные и конечные подчеркивания используются для встроенных методов, таких как__init__, __bool__, и т.д.

Двойные начальные подчеркивания без конечных аналогов также являются соглашением, однако методы класса будутискромсанный переводчиком. Для переменных или имен основных функций различий не существует.

как свойства двойного подчеркивания могут влиять на унаследованный класс. Итак, со следующей настройкой:

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

если вы потом создадите дочерний экземпляр в python REPL, вы увидите ниже

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

Это может быть очевидным для некоторых, но застало меня врасплох в гораздо более сложной среде

и все они правильные. Я привел простой пример вместе с простым определением / значением.

Смысл:

some_variable --► это публично, каждый может увидеть это.

_some_variable --► это публично, каждый может увидеть это, но это соглашение, указывающее частное ...предупреждение Python не выполняет никаких мер.

__some_varaible --► Python заменяет имя переменной на _classname__some_varaible (искажение имени AKA) и уменьшает / скрывает ее видимость и больше напоминает приватную переменную.

Просто чтобы быть честным здесьСогласно документации Python

«Частные» переменные экземпляра, к которым нельзя получить доступ, кроме как внутри объекта, не существует в Python »

Пример:

class A():
    here="abc"
    _here="_abc"
    __here="__abc"


aObject=A()
print(aObject.here) 
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable 
#print(aObject.__here)

но некоторые лакомые кусочки отсутствуют. Единственное подчеркивание не совсем точнотолько что соглашение: если вы используетеfrom foobar import *и модульfoobar не определяет__all__ список, имена импортированные из модуляне надо включают в себя те, которые с подчеркиванием. Скажем такв основном соглашение, так как этот случай - довольно туманный угол ;-).

Соглашение о нижнем подчеркивании широко используется не только длячастный имена, но и для того, что C ++ будет называтьзащищенный например, имена методов, которые полностью предназначены для переопределения подклассами (даже те, которыеимеют быть переопределенным, так как в базовом классе ониraise NotImplementedError! -) часто имена, начинающиеся с подчеркивания, для указания кодус помощью экземпляры этого класса (или подклассов), для которых указанные методы не предназначены для непосредственного вызова.

Например, чтобы создать потокобезопасную очередь с дисциплиной очереди, отличной от FIFO, необходимо импортировать очередь, подклассы Queue.Queue и переопределить такие методы, как_get а также_put; «код клиента» никогда не вызывает эти («перехватывать») методы, а скорее («организующие») публичные методы, такие какput а такжеget (это известно какШаблонный метод шаблон проектирования - см., например,Вот для интересной презентации, основанной на видео моей беседы на эту тему, с добавлением краткого изложения стенограммы).

 Vicrobot31 авг. 2018 г., 15:36
@AlexMartelli А почему он их не импортирует? я имею в виду; какие процессы останавливают импорт?
 endolith30 янв. 2017 г., 16:39
Итак, как вы решаете, следует ли использовать_var_name или использоватьvar_name + исключая это из__all__?
 Vicrobot31 авг. 2018 г., 15:12
@AlexMartelli Обсуждается ли это правило, связанное с импортом, где-то в документации или где-либо еще?
 abarnert25 апр. 2018 г., 19:15
@endolith Используйте начальное подчеркивание, чтобы сообщить читателю вашего кода, что он, вероятно, не должен использовать это (например, потому что вы можете изменить его в версии 2.0 или даже 1.1); использовать явный__all__ всякий раз, когда вы хотите сделать модульfrom spam import * дружелюбный (в том числе у интерактивного переводчика). Так что в большинстве случаев ответобе.

говоритьЯ просто сделаю это немного проще, записав, что он сказал:

Намерение двойного подчеркивания не было о частной жизни. Намерение было использовать именно так, как это

class Circle(object):

    def __init__(self, radius):
        self.radius = radius

    def area(self):
        p = self.__perimeter()
        r = p / math.pi / 2.0
        return math.pi * r ** 2.0

    def perimeter(self):
        return 2.0 * math.pi * self.radius

    __perimeter = perimeter  # local reference


class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

Это на самом деле противоположность частной жизни, это все о свободе. Это делает ваши подклассы свободными, чтобы переопределить любой один метод, не ломая другие.

Скажем, вы не держите местную ссылку наperimeter вCircle, Теперь производный классTire отменяет реализациюperimeterбез прикосновенияarea, Когда вы звонитеTire(5).area()в теории это все еще следует использоватьCircle.perimeter для вычисления, но на самом деле он используетTire.perimeter, что не является предполагаемым поведением. Вот почему нам нужна местная ссылка в Circle.

Но почему__perimeter вместо_perimeter? Потому что_perimeter все еще дает производному классу возможность переопределить:

class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

    _perimeter = perimeter

Двойное подчеркивание имеет искажение имени, поэтому существует очень небольшая вероятность того, что локальная ссылка в родительском классе получит переопределение в производном классе. таким образомделает ваши подклассы свободными для переопределения любого одного метода, не нарушая другие».

Если ваш класс не будет унаследован, или переопределение метода ничего не нарушает, тогда вам просто не нужно__double_leading_underscore.

речь идет не только о методах. Функции и объекты в модулях обычно имеют префикс с одним подчеркиванием и могут иметь префикс с двумя.

Но, например, имена __double_underscore не искажаются в модулях. Что происходит, так это то, что имена, начинающиеся с одного (или более) подчеркивания, не импортируются, если вы импортируете все из модуля (из модуля import *), а также имена не отображаются в справке (module).

 Bentley407 апр. 2012 г., 17:19
Кроме того, имена, начинающиеся с одного или нескольких подчеркиваний, которые имеют два или более завершающих подчеркивания, снова ведут себя как любое другое имя.

другие ответы выражают их довольно хорошо. Использование намного сложнее определить.

Вот как я это вижу:

_

Должен использоваться для указания того, что функция не предназначена для публичного использования, как, например, API. Это и ограничение импорта заставляют его вести себя какinternal в с #.

__

Следует использовать, чтобы избежать коллизии имен в иерархии наследования и избежать позднего связывания. Очень похоже на личное в C #.

==>

Если вы хотите указать, что что-то не для публичного использования, но оно должно действовать какprotected использование_, Если вы хотите указать, что что-то не для публичного использования, но оно должно действовать какprivate использование__.

Это также цитата, которая мне очень нравится:

Проблема в том, что автор класса может на законных основаниях думать, что «это имя атрибута / метода должно быть закрытым, доступным только из определения этого класса» и использовать соглашение __private. Но позже пользователь этого класса может создать подкласс, который законно нуждается в доступе к этому имени. Таким образом, либо суперкласс должен быть изменен (что может быть трудным или невозможным), либо код подкласса должен использовать искаженные вручную имена (который в лучшем случае уродлив и хрупок).

Но проблема в том, что, на мой взгляд, если нет среды IDE, которая предупреждает вас при переопределении методов, обнаружение ошибки может занять некоторое время, если вы случайно переопределили метод из базового класса.

что выглядит как кортеж с подчеркиванием, как в

def foo(bar):
    return _('my_' + bar)

В этом случае происходит то, что _ () является псевдонимом для функции локализации, которая работает с текстом, чтобы поместить его на нужный язык и т. Д. В зависимости от локали. Например, Sphinx делает это, и вы найдете среди импорта

from sphinx.locale import l_, _

а в sphinx.locale _ () назначается псевдонимом некоторой функции локализации.

__foo__Это просто соглашение, способ для системы Python использовать имена, которые не будут конфликтовать с именами пользователей.

_fooЭто просто соглашение, способ для программиста указать, что переменная является закрытой (что бы это ни значило в Python).

__foo: это имеет реальное значение: переводчик заменяет это имя на_classname__foo как способ гарантировать, что имя не будет совпадать с аналогичным именем в другом классе.

Никакая другая форма подчеркивания не имеет значения в мире Python.

В этих соглашениях нет разницы между классом, переменной, глобальным и т. Д.

 Bibhas Debnath09 мая 2013 г., 10:03
Только что наткнулся__foo и любопытно. Как это может совпадать с аналогичными именами методов с другими классами? Я имею в виду, вы все еще должны получить к нему доступ, какinstance.__foo()(если бы он не был переименован переводчиком), верно?
 dotancohen13 июн. 2013 г., 15:28
Этот парень говорится, чтоfrom module import * не импортирует объекты с префиксом подчеркивания. Следовательно,_foo это больше, чем просто соглашение.
 naught10126 янв. 2015 г., 04:11
@Bibhas: если классB класс подклассовAи оба реализуютfoo(), тогдаB.foo() переопределяет.foo() унаследованный отA, ЭкземплярB будет иметь доступ только кB.foo()кроме как черезsuper(B).foo().

Ваш ответ на вопрос