Почему у некоторых функций есть двойные подчеркивания "__" перед и после имени функции?
Вопрос о подчеркивании в именах функций в Python
Я заметил, что подчеркивания в именах функций и переменных в Python встречаются довольно часто, и мне интересно, является ли это требованием языка или всего лишь соглашением о стиле?
Кроме того, не могли бы вы перечислить и объяснить, какие функции обычно имеют подчеркивания, и почему (например, __init__
)?
5 ответ(ов)
Другие ответчики правы, описывая двойные подчеркивания в начале и конце имени как соглашение о наименовании для "специальных" или "магических" методов.
Хотя вы можете вызывать эти методы напрямую (например, [10, 20].__len__()
), наличие подчеркиваний указывает на то, что эти методы предназначены для косвенного вызова (например, len([10, 20])
). Большинство операторов в Python имеют соответствующий "магический" метод (например, a[x]
— это обычный способ вызова a.__getitem__(x)
).
Добавил пример для понимания использования __ в Python. Вот список всех __
https://docs.python.org/3/genindex-all.html#_
Определённые классы идентификаторов (кроме ключевых слов) имеют особое значение. Любое использование * имен, в любом другом контексте, не соответствующее явно задокументированному использованию, подвержено поломке без предупреждения.
Ограничение доступа с помощью __
"""
Идентификаторы:
- Содержат только (A-z, 0-9 и _)
- Начинаются с строчной буквы или _
- Один ведущий _ : частный
- Два ведущих __ : строго частный
- Начинается и заканчивается __ : специальное имя объекта/метода, определяемое языком
- Имена классов начинаются с заглавной буквы.
"""
class BankAccount(object):
def __init__(self, name, money, password):
self.name = name # Публичный
self._money = money # Приватный: уровень пакета
self.__password = password # Супер приватный
def earn_money(self, amount):
self._money += amount
print("Зарплата получена: ", amount, " Обновлённый баланс: ", self._money)
def withdraw_money(self, amount):
self._money -= amount
print("Деньги сняты: ", amount, " Обновлённый баланс: ", self._money)
def show_balance(self):
print(" Текущий баланс: ", self._money)
account = BankAccount("Hitesh", 1000, "PWD") # Инициализация объекта
# Вызов метода
account.earn_money(100)
# Показать баланс
print(account.show_balance())
print("ПУБЛИЧНЫЙ ДОСТУП:", account.name) # Публичный доступ
# account._money доступен, потому что он только скрыт в соответствии с соглашением
print("ЗАЩИЩЁННЫЙ ДОСТУП:", account._money) # Защищённый доступ
# account.__password вызовет ошибку, но account._BankAccount__password не вызовет,
# потому что __password - сверхприватный
print("ЧАСТНЫЙ ДОСТУП:", account._BankAccount__password)
# Вызов метода
account.withdraw_money(200)
# Показать баланс
print(account.show_balance())
# account._money доступен, потому что он только скрыт в соответствии с соглашением
print(account._money) # Защищённый доступ
В данном примере мы видим, как работает механизм ограничения доступа в Python, использующий одинарные и двойные подчёркивания. Одинарный подчёркиватель перед именем атрибута указывает на его защищённый статус, в то время как двойной подчёркиватель предоставляет более строгую защиту, создавая "имя" атрибута, которое включает имя класса.
Использование метода с нижним подчеркиванием в именах действительно является распространенной практикой, особенно когда нужно различать методы родительского и дочернего классов. Это позволяет избежать конфликтов имен и явно указывает на то, что метод _worker
предназначен для переопределения в дочернем классе.
В вашем примере вы используете миксин ThreadableMixin
, который реализует метод start_worker
, вызывающий метод worker
. Важно отметить, что внутри этого метода происходит вызов _worker
- это говорит о том, что вы ожидаете, что дочерний класс реализует этот метод, предоставляя свою собственную логику.
Пример кода, который вы представили, демонстрирует, как в классе Handler
переопределяется метод _worker
. Вопреки обычной практике именования, использование нижнего подчеркивания в начале имени метода (_worker
) указывает на то, что он предназначен для внутреннего использования, но при этом позволяет дочерним классам реализовать собственную версию этого метода. Это полезно для управления наследованием, так как соблюдается определенная структура и предсказуемость, когда дело доходит до работы с методами.
Таким образом, данная практика помогает поддерживать чистоту и организованность кода, а также облегчает понимание его структуры другими разработчиками.
Данная конвенция используется для специальных переменных или методов (так называемых "магических методов"), таких как __init__
и __len__
. Эти методы обеспечивают специальные синтаксические функции или выполняют определённые действия.
Например, __file__
указывает на расположение файла Python, а __eq__
вызывается при выполнении выражения a == b
.
Пользователь, конечно, может создать свой собственный специальный метод, что является довольно редким случаем, но чаще всего может изменять некоторые из встроенных специальных методов (например, инициализация класса с помощью __init__
, который выполняется первым при создании экземпляра класса).
class A:
def __init__(self, a): # используем специальный метод '__init__' для инициализации
self.a = a
def __custom__(self): # кастомный специальный метод. Его можно почти не использовать
pass
В Python использование подчеркивания в имени функции указывает на то, что функция предназначена для внутреннего использования и не должна вызываться напрямую пользователями. Это соглашение, которое показывает, что функция является "приватной" и не входит в публичный API модуля. Однако следует отметить, что это соглашение не является строгим ограничением, и пользователи все равно могут вызывать такую функцию, если они решат это сделать.
Как создать декораторы функций и объединить их?
Как получить исходный код функции Python?
Декораторы с параметрами?
Как вызвать функцию из другого .py файла?
Следует ли добавлять запятую после последнего аргумента в вызове функции? [закрыто]