Нашли ошибку?
Скачать чистый
урок 2 из 4≈ 15 минупражнения: 0 из 3

Свойства

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

Python запустится при первом выполнении

В прошлом уроке баланс карты читался методом: card.balance(). Работает, но выглядит странно — баланс скорее атрибут карты, чем действие. Python позволяет оставить внутренний _balance спрятанным и при этом читать баланс как атрибут, без скобок. Для этого есть свойства (property).

@property

Строка @property перед методом — это декоратор (decorator): он меняет то, как работает метод под ним. Метод с @property вызывается сам, когда атрибут читают, — скобки не нужны. Например, у заказа статус хранится во внутреннем _status, а читается свойством status:

[ ]Статус заказа — свойство
class Order:
    def __init__(self, number):
        self._number = number
        self._status = "новый"

    @property
    def number(self):
        return self._number

    @property
    def status(self):
        return self._status

    def pay(self):
        if self._status == "оплачен":
            return False  # дважды не оплачивают
        self._status = "оплачен"
        return True


order = Order(17)
print(order.number, order.status)  # без скобок
print(order.pay(), order.status)
print(order.pay(), order.status)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
17 новый
True оплачен
False оплачен

Снаружи order.status выглядит как обычный атрибут, но записать в него нельзя: у свойства есть только «чтение» — геттер (getter). Так получается атрибут только для чтения:

[ ]В свойство нельзя записатьошибка: AttributeError
order.status = "отменён"
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
AttributeError: property 'status' of 'Order' object has no setter

Менять статус можно только методами заказа — например, pay(), который не даст оплатить заказ дважды. Так же стоит поступить с балансом подарочной карты.

[ ]Упражнение 1Баланс карты свойством решено

Допишите класс GiftCard: сделайте balance свойством, которое возвращает _balance. Методы pay и top_up уже есть.

class GiftCard:
    def __init__(self, amount):
        self._balance = amount

    def balance(self):
        ...

    def pay(self, amount):
        if amount > self._balance:
            return False
        self._balance -= amount
        return True

    def top_up(self, amount):
        if amount <= 0:
            return False
        self._balance += amount
        return True

[ ]Свойство со скобкамиошибка: TypeError
order.number()
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
TypeError: 'int' object is not callable

Вычисляемый атрибут

Свойство не обязано возвращать сохранённый атрибут — оно может вычислять значение каждый раз, когда его читают. Например, сумма корзины: её не нужно хранить и обновлять при каждом add, достаточно посчитать по товарам:

[ ]Упражнение 2Сумма и число товаров решено

Допишите класс Cart: свойство total возвращает сумму цен товаров, свойство count — число товаров в корзине.

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price


class Cart:
    def __init__(self):
        self.items = []

    def add(self, product):
        self.items.append(product)

    # свойства total и count

Вычисляемое свойство всегда актуально: оно считается заново при каждом чтении. Значение, вычисленное один раз в __init__, устареет, как только поменяются данные.

[ ]Упражнение 3Размер по объёму решено

Допишите класс Drink: свойство size возвращает размер по объёму volume — до 250 мл включительно "S", до 350 мл включительно "M", больше — "L". Если объём изменился, размер должен измениться вместе с ним.

class Drink:
    def __init__(self, name, volume):
        self.name = name
        self.volume = volume

    @property
    def size(self):
        ...

Свойство или метод

Вопрос

Что из этого естественнее сделать свойством, а не методом?

Правило выбора:

Свойство Метод
характеристика объекта: balance, total, size действие: pay, add, remove
без параметров с параметрами или без
ничего не меняет в объекте может менять состояние
вычисляется быстро может работать долго

В следующем уроке у свойства появится и запись — с проверкой значения.

Нашли ошибку?