Какую роль играют префиксы с нижним подчеркиванием в именах методов и атрибутов в Python?

Ответ

В Python префиксы с нижним подчеркиванием (_) в именах переменных, методов и атрибутов используются для указания их области видимости и специального поведения. Это часть соглашений по написанию кода (PEP 8) и механизмов языка.

  1. _single_leading_underscore (одно ведущее подчеркивание)

    • Назначение: Указывает, что переменная или метод предназначены для внутреннего использования внутри модуля или класса. Это соглашение, а не синтаксическое ограничение. Интерпретатор не запрещает доступ к таким атрибутам извне, но это считается дурным тоном.
    • Пример: from module import * не импортирует имена, начинающиеся с _.
      class MyClass:
      def _internal_method(self):
          return "Это внутренний метод класса"
  2. __double_leading_underscore (два ведущих подчеркивания)

    • Назначение: Включает механизм Name Mangling (искажение имен). Интерпретатор автоматически изменяет имя атрибута, чтобы избежать случайных коллизий имен в подклассах.
    • Как работает: Имя __spam внутри класса MyClass будет преобразовано в _MyClass__spam.
      
      class MyClass:
      def __mangled_method(self):
          print("Вызван метод из MyClass")

    class SubClass(MyClass): def __mangled_method(self): print("Вызван метод из SubClass")

    Методы не переопределяют друг друга из-за искажения имен

    obj._MyClassmangled_method() и obj._SubClassmangled_method()

  3. __double_leading_and_trailing_underscore__ (двойные подчеркивания с обеих сторон)

    • Назначение: Зарезервировано для специальных или "магических" методов (dunder methods). Эти методы вызываются Python неявно в определенных ситуациях.
    • Примеры: __init__ (конструктор), __str__ (для str()), __add__ (для оператора +).

      class Number:
      def __init__(self, value):
          self.value = value
      
      def __add__(self, other):
          return self.value + other.value
  4. single_trailing_underscore_ (одно подчеркивание в конце)

    • Назначение: Используется по соглашению, чтобы избежать конфликтов с ключевыми словами Python.
      # Нельзя: def my_func(class):
      # Можно:
      def my_func(class_):
      print(class_)

Ответ 18+ 🔞

О, слушай, вот эта хуйня с подчёркиваниями в питоне — это ж целая наука, блядь! Как будто секретный язык для посвящённых. Сейчас разжуем, чтобы не путаться.

Вот смотри, есть у нас эти самые подчёркивания, и они, сука, не просто так. Каждое — как отдельный сигнал, блядь, для интерпретатора и для других программистов.

Во-первых, одно подчёркивание в начале: _internal Это типа вежливый намёк, блядь. Не крик, а шёпот: «Чувак, это для внутреннего пользования, нахуй. Не лезь сюда, если не хочешь, чтобы всё развалилось завтра». Это соглашение, ёпта, а не закон. Интерпретатор тебя не остановит, если ты полезешь, но все вокруг будут смотреть, как на мудака.

class ТайнаяКухня:
    def _секретный_соус(self):
        return "рецепт от бабки"

Импорт через звёздочку (from module import *) эту переменную проигнорит, как будто её нет. Умно, блядь.

Во-вторых, два подчёркивания в начале: __private А вот это уже поинтереснее, ёбана! Это не просто намёк — это Name Mangling, или, по-нашему, «извращение имён». Интерпретатор берёт и насильно, блядь, переименовывает атрибут, чтобы в наследниках не было конфликтов. Получается что-то вроде _ИмяКласса__атрибут.

class Родитель:
    def __мой_метод(self):
        print("Я из Родителя!")

class Ребёнок(Родитель):
    def __мой_метод(self):
        print("А я из Ребёнка!")

# По факту создаются два РАЗНЫХ метода:
# _Родитель__мой_метод и _Ребёнок__мой_метод. Никакого переопределения, пиздец!

Хитро, да? Чтобы случайно не наступить на грабли в сложной иерархии.

В-третьих, подчёркивания с двух сторон: __магия__ Это, блядь, святая святых — магические, или dunder-методы. Их трогать нельзя, их нужно только использовать. Они запускаются сами в нужный момент: создание объекта (__init__), вывод на печать (__str__), сложение (__add__). Твоя задача — только правильно их написать.

class СамодельноеЧисло:
    def __init__(self, цифра):
        self.цифра = цифра

    def __add__(self, другое):
        return self.цифра + другое.цифра  # Теперь объекты можно складывать плюсиком!

И наконец, подчёркивание в конце: class_ Это просто костыль, ёпта, от безысходности. Когда тебе нужна переменная с именем, которое уже занято ключевым словом языка. Не можешь назвать class — назови class_. И всем понятно, и интерпретатор не орёт.

# Так нельзя, блядь, будет ошибка:
# def функция(class):

# А так — пожалуйста, красота:
def функция(class_):
    print(f"Принят класс: {class_}")

Вот и вся философия, блядь. Не так страшен чёрт, как его малюют. Главное — не путать, где намёк, где защита, а где магия, и тогда код будет не только работать, но и выглядеть, как у взрослого дяди.