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

Как используешь инкапсуляцию на практике?

1.8 Middle🔥 161 комментариев
#Python Core#Архитектура и паттерны

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

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

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

Инкапсуляция на практике

Инкапсуляция — это принцип скрытия внутренней реализации объекта и предоставления контролируемого доступа к его состоянию и поведению. В Python это делается через соглашение о названиях и использование свойств (properties).

Основные уровни доступа

В Python нет строгих модификаторов доступа (как public/private в Java), но есть соглашения:

class BankAccount:
    # Публичный атрибут
    account_number = "123456"
    
    # Защищённый атрибут (соглашение: используй осторожно)
    _balance = 1000
    
    # Приватный атрибут (Name mangling, двойное подчёркивание)
    __pin = "1234"

1. Приватные атрибуты с двойным подчёркиванием

Двойное подчёркивание включает name mangling — атрибут переименовывается во время компиляции:

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance
    
    def get_balance(self):
        return self.__balance
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            return True
        return False

account = BankAccount(1000)
print(account.get_balance())  # 1000

2. Свойства (Properties) — правильный способ

Используй @property для контролируемого доступа к атрибутам:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Температура ниже абсолютного нуля")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32

temp = Temperature(25)
print(temp.celsius)      # 25
print(temp.fahrenheit)   # 77.0
temp.celsius = 30        # Работает setter с валидацией

3. Практический пример: User с инкапсуляцией

import re
from datetime import datetime

class User:
    def __init__(self, name, email, password):
        self._name = name
        self._email = email
        self.__password_hash = hash(password)
        self._created_at = datetime.now()
        self._login_attempts = 0
    
    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self, value):
        if not value or len(value) < 2:
            raise ValueError("Имя должно быть минимум 2 символа")
        self._name = value
    
    @property
    def email(self):
        return self._email
    
    @email.setter
    def email(self, value):
        if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$', value):
            raise ValueError("Неправильный формат email")
        self._email = value
    
    def set_password(self, old_password, new_password):
        if hash(old_password) != self.__password_hash:
            self._login_attempts += 1
            if self._login_attempts >= 3:
                raise PermissionError("Слишком много попыток")
            raise ValueError("Неправильный пароль")
        
        self.__password_hash = hash(new_password)
        self._login_attempts = 0
        return True
    
    def verify_password(self, password):
        return hash(password) == self.__password_hash

user = User("Иван", "ivan@example.com", "secret123")
print(user.name)           # Иван
user.name = "Петр"        # ОК
user.verify_password("secret123")  # True

4. Инкапсуляция с наследованием

class Animal:
    def __init__(self, name):
        self._name = name
        self.__species = None
    
    def _get_sound(self):
        return "..."

class Dog(Animal):
    def _get_sound(self):
        return "Гав!"
    
    def bark(self):
        return self._get_sound()

dog = Dog("Шарик")
print(dog.bark())  # Гав!

5. Использование slots для оптимизации

class Point:
    __slots__ = ['x', 'y']
    
    def __init__(self, x, y):
        self.x = x
        self.y = y

point = Point(10, 20)
print(point.x, point.y)  # 10 20

Резюме

  • __private — Name mangling, скрывает от случайного доступа
  • _protected — Соглашение для наследников и внутреннего использования
  • @property — Правильный способ контроля доступа с валидацией
  • slots — Оптимизация для часто создаваемых объектов
  • Правило: Минимум публичного интерфейса, максимум инкапсуляции
Как используешь инкапсуляцию на практике? | PrepBro