May 25

Геттеры и сеттеры в Python

Постигаем геттеры и сеттеры

Для начала разберемся, что это такое и когда они нам могут пригодиться. Простыми словами, геттер получает значение приватного атрибута, а сеттер его устанавливает, вот и все.

С их помощью можно поддержать инкапсуляцию (получать доступ к приватным атрибутам) или каким-либо дополнительным образом провалидировать или обработать значения.

Пара слов о property

Примеры сразу будем рассматривать с удобными аннотациями @property - свойствами. Это более "питонический" путь работы с поведением атрибутов, такими как получение, настройка и удаление.

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

Как связаны свойства с геттерами и сеттерами? Когда мы получаем доступ к свойству, то автоматически вызывается связанный с ним getter-метод. Когда мы пытаемся изменить свойство, соответственно будет вызван setter-метод.

А теперь перейдем к практике.

Пример использования

Создадим класс Product, чтобы мы могли провернуть с ним некоторые процедуры:

  • создать конкретный продукт, задав ему имя и базовую стоимость (без НДС)
  • получить стоимость продукта с / без НДС
  • назначить новую цену, введя сумму с НДС, выполнить расчет базовой стоимости и записать ее в приватный атрибут.
class Product:  
    def __init__(self, name: str, base_price: float) -> None:  
        self.name = name  
        self.__base_price = base_price  
        self.__vat_percent = 0.13  
  
    @property  
    def price(self) -> float:  
        return round(self.__base_price * (1 + self.__vat_percent), 2)  
  
    @price.setter  
    def price(self, value: float) -> None:  
        # пересчитываем базовую цену, т.к. передаем в value цену с НДС
        self.__base_price = round(value / (1 + self.__vat_percent), 2)  
  
    @property  
    def base_price(self) -> float:  
        return self.__base_price

Сразу определим, что НДС будет равен 13%.

Под капотом некоторые обработки для свойств:

  • Округление и рассчет цены с НДС при получении цены через свойство price
  • Рассчет базовой стоимости по полученной стоимости с НДС, округление и установка значения в приватный атрибут __base_price

Класс описали, посмотрим теперь на пример использования:

coffee = Product(name="Флэт уайт", base_price=300)  # Создаем наш кофе с ценой до НДС = 300 р.

print(coffee.name)  # Флэт уайт | Здесь просто название
print(coffee.price)  # 339.0 | Цена рассчитана с НДС, это произошло автоматически
  
coffee.price = 350  # Устанавливаем новую цену для кофе, сумма сразу с НДС, чтобы произошла корректная обработка и вычисление базовой стоимости
print(coffee.price)  # >>> 349.99  | Получаем цену с НДС. Не равно 350 из-за округлений при записи
print(coffee.base_price)  # >>> 309.73  | Базовая цена без НДС

Пример получился лаконичным, так как мы производим все вычисления, просто обращаясь к свойствам, не вызываем явные методы для этих операций. При этом, напрямую не обращаемся к приватным атрибутам, не нарушая принцип инкапсуляции.

Маленький бонус: deleter

Хоть в нашем примере это не имеет особого смысла, но для рассмотрения еще 1 свойства можно попробовать обновить пример так, чтобы использовать deleter. Это свойство уместно, когда нужно удалить атрибут или сбросить его в изначальное состояние, или обработать удаление атрибута каким-то определенным образом.

Добавим в наш пример с Product следующее свойство:

@price.deleter
def price(self):
	self.__base_price = 0

Тогда если мы удалим атрибут, значение __base_price просто сбросится в ноль. Проверим:

del coffee.price  
print(coffee.price)  # 0.0

Выводы

Геттеры и сеттеры:

✅ помогают скрыть реализацию и сохранить инкапсуляцию
✅ позволяют валидировать или изменять данные при доступе к ним
✅ обеспечивают простой и читаемый интерфейс (без явных методов)

Лучше использовать методы вместо свойств, если:

  • операция не выглядит как "доступ к данным"
  • требуется более сложная логика


Мой telegram-канал, присоединяйтесь :)

⬇⬇⬇

https://t.me/python3_with_love