← Назад к вопросам

В чем разница между _ и __?

1.8 Middle🔥 121 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между _ и __

В Python подчёркивания имеют специальное значение. Это соглашение (convention), которое сообщает другим разработчикам о намерении использования переменной или метода.

Одиночное подчёркивание (_)

Означает: Внутренняя переменная / метод, использовать осторожно.

Это просто соглашение, Python не защищает такие переменные. Для других разработчиков это сигнал: "Это внутренняя реализация, не рассчитывай на её стабильность".

class Calculator:
    def __init__(self):
        self._internal_cache = {}  # Сигнал: используй осторожно
    
    def _calculate_hash(self, value):
        # Приватный метод (по соглашению)
        return hash(value)
    
    def public_method(self):
        # Публичный метод
        result = self._calculate_hash(42)
        return result

calc = Calculator()
calc.public_method()  # OK
calc._calculate_hash(10)  # Технически работает, но не следует это делать

Двойное подчёркивание (__)

Означает: Приватное, с name mangling (переименование имён).

Python активно защищает такие переменные с помощью механизма name mangling. Имя переименовывается в _ClassName__attribute.

class Person:
    def __init__(self, name):
        self.__password = "secret"  # Подлинная приватность
    
    def __private_method(self):
        # Приватный метод
        return self.__password
    
    def get_password(self):
        return self.__private_method()

person = Person("Alice")

# Прямой доступ не работает
# person.__password  # AttributeError: 'Person' object has no attribute '__password'

# Но можно получить через name mangling
print(person._Person__password)  # "secret" — работает, но плохая практика!

# Или через публичный метод
print(person.get_password())  # "secret" — правильно

Как работает Name Mangling

class Example:
    def __init__(self):
        self.__attr = "private"
        self._attr = "protected"

e = Example()

print(dir(e))
# Выведет:
# [..., '_Example__attr', '_attr', ...]
#      ↑ переименовано      ↑ не переименовано

Практический пример

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance  # Истинная приватность
        self._interest_rate = 0.05  # Внутренняя, но не скрыта
    
    def __calculate_interest(self):
        # Приватный метод
        return self.__balance * self._interest_rate
    
    def withdraw(self, amount):
        # Публичный метод
        if amount <= self.__balance:
            self.__balance -= amount
            return True
        return False
    
    def get_balance(self):
        # Публичный доступ к приватным данным
        return self.__balance

account = BankAccount(1000)
account.withdraw(100)
print(account.get_balance())  # 900

# Попытка прямого доступа
# account.__balance  # ❌ AttributeError
account._interest_rate = 0.1  # ⚠️ Можно, но не следует

Когда использовать

СлучайИспользуйПример
Публичное APIБез подчёркиванияdef save(self)
Внутренняя реализация_singledef _validate(self)
Избегай прямого доступа_singleself._cache
Полная приватность__doubleself.__secret_key
Избегаем конфликтов имён__doubleself.__id (в наследовании)

Почему __ важен в наследовании

class Parent:
    def __init__(self):
        self.__id = "parent"
        self._name = "parent"

class Child(Parent):
    def __init__(self):
        super().__init__()
        self.__id = "child"  # Не конфликтует с Parent.__id!
        self._name = "child"  # Перезаписывает Parent._name

child = Child()
print(child._name)  # "child" (переписано)
print(child._Parent__id)  # "parent" (защищено)
print(child._Child__id)  # "child" (защищено отдельно)

Важный нюанс

name mangling срабатывает только для атрибутов, начинающихся с __ и НЕ заканчивающихся на __:

class Example:
    def __init__(self):
        self.__private = 1  # Будет переименовано
        self.__dunder__ = 2  # НЕ будет переименовано (спецметоды)
        self___triple = 3  # Будет переименовано как _Example___triple

e = Example()
print(e.__dunder__)  # 2 — работает

Выводы: _ это соглашение, __ это механизм защиты. В большинстве случаев лучше использовать _ для внутренних методов и атрибутов, а __ только когда действительно нужна защита от переопределения в подклассах.

В чем разница между _ и __? | PrepBro