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

Расскажи про три типа инкапсуляции в Python

2.0 Middle🔥 101 комментариев
#Python Core

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

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

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

Три типа инкапсуляции в Python

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

1. Public атрибуты (без подчеркивания)

Это атрибуты, доступные всем. Они используются для всех данных, которые должны быть доступны извне класса.

class User:
    def __init__(self, name, email):
        self.name = name      # public атрибут
        self.email = email    # public атрибут
    
    def get_info(self):       # public метод
        return f"{self.name} ({self.email})"

user = User("John", "john@example.com")
print(user.name)          # Доступно: John
user.email = "new@example.com"  # Можно изменить

Характеристики:

  • Видны всем
  • Можно читать и изменять
  • Обычно требуют от разработчика ответственности использовать правильно
  • Инкапсуляция: минимальная

2. Protected атрибуты (одно подчеркивание _)

Одно подчеркивание — это соглашение, что атрибут "внутренний" и его не следует использовать извне класса.

class BankAccount:
    def __init__(self, balance):
        self._balance = balance  # protected атрибут
    
    def _calculate_interest(self, rate):  # protected метод
        return self._balance * rate
    
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
    
    def withdraw(self, amount):
        if amount <= self._balance:
            self._balance -= amount

account = BankAccount(1000)
account.deposit(500)
# Технически можно сделать:
# account._balance = -999999
# Но это считается плохой практикой

Характеристики:

  • Доступны технически, но только для разработчика класса и подклассов
  • Сигнализируют: "Это внутренняя реализация, не трогайте"
  • IDE/linter могут предупредить об использовании
  • Инкапсуляция: средняя
  • Часто используются в подклассах (наследование)

3. Private атрибуты (двойное подчеркивание __)

Двойное подчеркивание в начале имени активирует "name mangling" — механизм Python для скрытия атрибутов.

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance  # private атрибут
        self.__pin = 1234         # private атрибут
    
    def __validate_pin(self, pin):  # private метод
        return pin == self.__pin
    
    def withdraw(self, amount, pin):
        if self.__validate_pin(pin) and amount <= self.__balance:
            self.__balance -= amount
            return True
        return False
    
    def get_balance(self, pin):
        if self.__validate_pin(pin):
            return self.__balance
        return None

account = BankAccount(1000)

# Так нельзя:
# print(account.__balance)  # AttributeError!
# account.__balance = -999  # Не сработает

# А вот так можно (но не следует):
print(account._BankAccount__balance)  # 1000 (name mangling)

Механизм name mangling:

Когда вы пишете self.__attr, Python переименовывает его в _ClassName__attr:

class MyClass:
    def __init__(self):
        self.__secret = "hidden"

obj = MyClass()
print(dir(obj))  # Видим _MyClass__secret
print(obj._MyClass__secret)  # "hidden"

Характеристики:

  • Действительно скрыты от внешнего доступа
  • Вызывают AttributeError при попытке доступа
  • Защита от случайного использования
  • Можно обойти через name mangling (но это явный признак, что вы нарушаете инкапсуляцию)
  • Инкапсуляция: максимальная

Практический пример: трехуровневая инкапсуляция

class DataProcessor:
    def __init__(self, data):
        self.raw_data = data          # public - для доступа клиентом
        self._cache = {}               # protected - для подклассов
        self.__processed_count = 0     # private - внутренняя реализация
    
    def process(self):
        """public метод"""
        result = self._prepare_data()  # используем protected
        self.__increment_counter()      # используем private
        return result
    
    def _prepare_data(self):           # protected метод
        """Подготовка данных - может переопределиться в подклассе"""
        if prepared in self._cache:
            return self._cache[prepared]
        
        prepared = [x.strip() for x in self.raw_data]
        self._cache[prepared] = prepared
        return prepared
    
    def __increment_counter(self):     # private метод
        """Только для внутреннего использования"""
        self.__processed_count += 1
    
    def get_stats(self):
        """public метод для получения статистики"""
        return {"processed": self.__processed_count}

processor = DataProcessor(["hello ", " world "])
print(processor.process())  # [hello, world]
print(processor.get_stats())  # {processed: 1}

Наследование и инкапсуляция

class Parent:
    def __init__(self):
        self.public = "открыто"
        self._protected = "защищено"
        self.__private = "скрыто"

class Child(Parent):
    def show_parent_data(self):
        print(self.public)       # OK
        print(self._protected)   # OK - доступно для подклассов
        # print(self.__private)  # ошибка - недоступно!
        print(self._Parent__private)  # OK - можно через name mangling

child = Child()
child.show_parent_data()

Когда использовать каждый уровень

Public (attr):

  • Часть публичного API
  • Данные, которые должны быть доступны клиентам
  • Простые структуры данных

Protected (_attr):

  • Внутренняя логика класса
  • Может быть переопределено в подклассе
  • Для разработчика фреймворка

Private (__attr):

  • Критическая внутренняя реализация
  • Не должна быть видна подклассам
  • Защита от случайного использования
  • Редко используется в Python (более популярен protected)

Философия Python

"We are all consenting adults here" — Python полагается на честность разработчика, а не на технические ограничения. Private и Protected — это соглашения, а не абсолютные ограничения. Это дает гибкость, но требует дисциплины.

Заключение

Три уровня инкапсуляции в Python:

  1. Public — открыто для всех
  2. Protected — для подклассов и расширений
  3. Private — только для внутреннего использования

Выбор уровня зависит от того, на кого вы разрабатываете класс — для себя, для тиммейтов, для фреймворка или для публичной библиотеки.