Почему некоторые функции имеют подчеркивание "__" до и после имени функции?
Это, кажется, происходит часто, и было интересно, было ли это требованием в языке 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 модуля. Тем не менее, это не обеспечивается языком и может быть вызвано пользователем, если он захочет это сделать.