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

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

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

7 ответов

Решение

Из 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: "Никогда не изобретайте такие имена; используйте их только как документированные".

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

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

Имена, окруженные двойным подчеркиванием, являются "особенными" для Python. Они перечислены в Справочнике по языку Python, раздел 3, "Модель данных".

Добавлен пример для понимания использования __ в 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

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

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)
    )

...

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

Например, file указывает местоположение файла Python, eq выполняется, когда выполняется выражение == 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

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

Другие вопросы по тегам