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

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

Мы умеем создавать классы с атрибутами и методами. Но что мешает кому-то написать account.balance = -1000 и обойти все проверки? Инкапсуляция — принцип сокрытия внутреннего состояния объекта и предоставления контролируемого доступа через методы.

Проблема открытых атрибутов

class BankAccount:
    def __init__(self, balance):
        self.balance = balance

account = BankAccount(1000)
account.balance = -999999   # никто не проверяет!
print(account.balance)      # -999999 — некорректное состояние

В Python нет настоящей private-защиты как в Java или C++. Вместо этого — соглашения, которые сообщают другим разработчикам: «этот атрибут внутренний».

Соглашение: одно подчёркивание _

Одно подчёркивание в начале — сигнал «я внутренний, не трогай без необходимости»:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius   # "не трогай напрямую"

    def get_celsius(self):
        return self._celsius

    def set_celsius(self, value):
        if value < -273.15:
            raise ValueError("Ниже абсолютного нуля")
        self._celsius = value

t = Temperature(25)
print(t.get_celsius())     # 25
t.set_celsius(100)
# t._celsius = -500  # технически можно, но это нарушение соглашения

Одно подчёркивание — конвенция, не принуждение. Python не запрещает обращаться к _celsius, но это говорит: «используешь на свой страх и риск».

Name mangling: двойное подчёркивание __

Двойное подчёркивание (__attr) включает механизм name mangling: Python переименовывает атрибут в _ClassName__attr, затрудняя случайный доступ снаружи:

class Person:
    def __init__(self, name, secret):
        self.name = name
        self.__secret = secret   # name mangling

    def reveal_secret(self):
        return f"Секрет {self.name}: {self.__secret}"

p = Person("Алиса", "боюсь пауков")
print(p.reveal_secret())   # Секрет Алисы: боюсь пауков

# print(p.__secret)   # AttributeError!
print(p._Person__secret)  # "боюсь пауков" — технически доступно, но некрасиво

Двойное подчёркивание не создаёт строгой приватности — скорее защищает от случайных коллизий имён в иерархиях наследования.

Property: атрибут + контроль через декоратор

Более питоничный способ — декоратор @property. Он позволяет обращаться к атрибуту как к обычному, но выполнять при этом логику:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise ValueError("Радиус должен быть положительным")
        self._radius = value

    @property
    def area(self):
        import math
        return math.pi * self._radius ** 2

c = Circle(5)
print(c.radius)   # 5   — вызывает getter
c.radius = 10     # вызывает setter с проверкой
print(c.area)     # 314.159... — вычисляется на лету

# c.radius = -1   # ValueError: Радиус должен быть положительным

@property — «умный атрибут»: снаружи выглядит как поле, внутри — метод. Это Python-идиом для контроля доступа без раздражающих get_x() / set_x().

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

В Python принят более свободный подход, чем в Java. Руководствуйтесь здравым смыслом:

  • _attr — внутренний атрибут, нежелательный для прямого использования снаружи.
  • __attr — атрибут, который не должен случайно переопределяться в подклассах.
  • @property — когда нужна валидация или вычисляемое значение за атрибутом-интерфейсом.
  • Публичный атрибут (без подчёркивания) — часть публичного API; менять его смысл — ломать совместимость.

Итог

  • Инкапсуляция — сокрытие внутреннего состояния и контроль доступа через методы.
  • _attr — соглашение «внутренний»; Python не запрещает доступ.
  • __attr — name mangling; переименовывается в _ClassName__attr.
  • @property — управляемый доступ с синтаксисом атрибута.
  • Python доверяет разработчику: нет строгой приватности, только соглашения.

Модуль 12 завершён. В следующем модуле применим всё, что изучили: напишем финальный проект — консольную телефонную книгу с классами и сохранением в JSON.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике