Почему некоторые функции подчеркивают «__» до и после имени функции?

425

Это «подчеркивание», кажется, происходит много, и мне было интересно, было ли это требованием в языке Python или просто условием?

Кроме того, кто-то может назвать и объяснить, какие функции имеют тенденцию подчеркивания и почему ( __init__например)?

Чак Теста
источник
8
@AustinHenley: не для двойного подчеркивания до и после имени. Вы думаете о подчеркивании исключительно перед именем.
@MackM Обратите внимание, что в этом вопросе спрашивается об подчеркивании до и после имени, а предложенная вами повторяющаяся цель запрашивает подчеркивание только перед именем. Хотя, я признаю, что некоторые ответы там также охватывают этот случай.
Георгий

Ответы:

527

Из Python PEP 8 - Руководство по стилю для кода Python :

Описательный: Стили именования

Следующие специальные формы, использующие начальное или конечное подчеркивание, распознаются (как правило, они могут сочетаться с любым условным обозначением):

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

  • single_trailing_underscore_: используется по соглашению, чтобы избежать конфликтов с ключевым словом Python, например

    Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore: при именовании атрибута класса вызывает искажение имени (внутри класса FooBar __booстановится _FooBar__boo; см. ниже).

  • __double_leading_and_trailing_underscore__: «волшебные» объекты или атрибуты, которые живут в управляемых пользователем пространствах имен. Например __init__, __import__или __file__. Никогда не изобретайте такие имена; используйте их только так, как задокументировано.

Обратите внимание, что имена с двойным начальным и конечным подчеркиванием по существу зарезервированы для самого Python: «Никогда не изобретайте такие имена; используйте их только как документированные».

Майкл Берр
источник
6
Раймонд также объясняет, почему вы хотите, чтобы поведение,
связанное
5
Таким образом, выбор между единственным подчеркиванием в начале и двойным подчеркиванием в имени похож на выбор между защищенным и закрытым в C ++ и Java? _single_leading_underscore могут быть изменены детьми, но __double_leading_underscore не может?
Алекс W
2
__double_leading_underscoreэто еще общественности , переменная просто переименованы , чтобы избежать столкновения.
cz
59

Другие респонденты правы в описании двойных начальных и конечных подчеркиваний как соглашения об именах для «специальных» или «магических» методов.

Хотя вы можете вызывать эти методы напрямую ( [10, 20].__len__()например), наличие подчеркивания является намеком на то, что эти методы предназначены для косвенного вызова ( len([10, 20])например). Большинство операторов python имеют связанный «магический» метод (например, a[x]это обычный способ вызова a.__getitem__(x)).

Раймонд Хеттингер
источник
5

На самом деле я использую имена методов _, когда мне нужно различать имена родительских и дочерних классов. Я прочитал некоторые коды, которые использовали этот способ создания родительско-дочерних классов. В качестве примера я могу предоставить этот код:

class ThreadableMixin:
   def start_worker(self):
       threading.Thread(target=self.worker).start()

   def worker(self):
      try:
        self._worker()
    except tornado.web.HTTPError, e:
        self.set_status(e.status_code)
    except:
        logging.error("_worker problem", exc_info=True)
        self.set_status(500)
    tornado.ioloop.IOLoop.instance().add_callback(self.async_callback(self.results))

...

и ребенок, у которого есть метод _worker

class Handler(tornado.web.RequestHandler, ThreadableMixin):
   def _worker(self):
      self.res = self.render_string("template.html",
        title = _("Title"),
        data = self.application.db.query("select ... where object_id=%s", self.object_id)
    )

...

Омадбек Оноров
источник
Разве это не то, для чего используется префикс двойного подчеркивания?
AMC
1

Это соглашение используется для специальных переменных или методов (так называемый «магический метод»), таких как __init__и __len__. Эти методы предоставляют специальные синтаксические функции или делают специальные вещи.

Например, __file__указывает местоположение файла Python, __eq__выполняется при выполнении a == bвыражения.

Пользователь, конечно, может создать специальный специальный метод, что является очень редким случаем, но часто может изменить некоторые из встроенных специальных методов (например, вы должны инициализировать класс тем, __init__который будет выполняться вначале, когда экземпляр класса). создано).

class A:
    def __init__(self, a):  # use special method '__init__' for initializing
        self.a = a
    def __custom__(self):  # custom special method. you might almost do not use it
        pass
Шагун Прути
источник
0

Добавлен пример, чтобы понять использование __ в python. Вот список всех __

https://docs.python.org/3/genindex-all.html#_

Определенные классы идентификаторов (помимо ключевых слов) имеют особое значение. Любое использование имен * в любом другом контексте, которое не следует явно задокументированному использованию, может быть прервано без предупреждения

Ограничение доступа с помощью __

"""
Identifiers:
-  Contain only (A-z, 0-9, and _ )
-  Start with a lowercase letter or _.
-  Single leading _ :  private
-  Double leading __ :  strong private
-  Start & End  __ : Language defined Special Name of Object/ Method
-  Class names start with an uppercase letter.
-

"""


class BankAccount(object):
    def __init__(self, name, money, password):
        self.name = name            # Public
        self._money = money         # Private : Package Level
        self.__password = password  # Super Private

    def earn_money(self, amount):
        self._money += amount
        print("Salary Received: ", amount, " Updated Balance is: ", self._money)

    def withdraw_money(self, amount):
        self._money -= amount
        print("Money Withdraw: ", amount, " Updated Balance is: ", self._money)

    def show_balance(self):
        print(" Current Balance is: ", self._money)


account = BankAccount("Hitesh", 1000, "PWD")  # Object Initalization

# Method Call
account.earn_money(100)

# Show Balance
print(account.show_balance())

print("PUBLIC ACCESS:", account.name)  # Public Access

# account._money is accessible because it is only hidden by convention
print("PROTECTED ACCESS:", account._money)  # Protected Access

# account.__password will throw error but account._BankAccount__password will not
# because __password is super private
print("PRIVATE ACCESS:", account._BankAccount__password)

# Method Call
account.withdraw_money(200)

# Show Balance
print(account.show_balance())

# account._money is accessible because it is only hidden by convention
print(account._money)  # Protected Access
Хите саху
источник