⚖️ Старый vs Новый: подходы к инкапсуляции
⚡ Кратко
Сравните два подхода и выбирайте более ясный и безопасный вариант, сохраняя старый синтаксис только для чтения существующего кода.
Подход 1. Прямой доступ к полям
Простой, но небезопасный способ. Внешний код может установить любое значение, даже некорректное.
class User:
def __init__(self, age: int) -> None:
self.age = age
user = User(25)
user.age = -5 # некорректное значение, но ничто не мешает
print(user.age) # -5
Подход 2. Геттеры и сеттеры
Классический объектно-ориентированный подход. Добавляет контроль, но делает интерфейс менее естественным.
class User:
def __init__(self, age: int) -> None:
self.__age = age
def get_age(self) -> int:
return self.__age
def set_age(self, value: int) -> None:
if value < 0:
raise ValueError("Возраст не может быть отрицательным")
self.__age = value
user = User(25)
user.set_age(30)
print(user.get_age())
# user.set_age(-5) # ValueError
Подход 3. Современный: @property
Сохраняет простоту прямого доступа и добавляет валидацию. Рекомендуется в Python.
class User:
def __init__(self, age: int) -> None:
self.__age = age
@property
def age(self) -> int:
return self.__age
@age.setter
def age(self, value: int) -> None:
if value < 0:
raise ValueError("Возраст не может быть отрицательным")
self.__age = value
user = User(25)
user.age = 30
print(user.age)
# user.age = -5 # ValueError
Сравнение
| Подход | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
| Прямой доступ | Простота, мало кода | Нет контроля, легко сломать объект | Простые структуры данных, датаклассы |
| Геттеры/сеттеры | Явный контроль, привычно в других языках | Многословность, непривычный синтаксис в Python | Интерфейсы, библиотеки, кросс-языковые проекты |
@property |
Чистый синтаксис, контроль, гибкость | Требует понимания декораторов | Производственный Python-код |
💡 Рекомендация: в Python предпочитайте
@property, когда нужен контролируемый доступ к атрибутам. Используйте геттеры/сеттеры методами, если проект или команда придерживаются такого стиля.