«Кофейная лавка» запускает карту лояльности. С каждой покупки на карту начисляется 5 % суммы баллами (округление вниз), баллами можно оплатить часть следующих покупок. Чем больше клиент потратил за всё время, тем выше уровень карты: до 5000 ₽ — «базовый», до 20 000 ₽ — «серебряный», от 20 000 ₽ — «золотой».
Баллы — те же деньги, поэтому главное требование — через публичный интерфейс баланс нельзя изменить в обход
правил.
В проекте пригодится весь модуль: внутренние атрибуты, свойства только для чтения, проверки и raise.
Шаг 1. Карта и начисление
Допишите класс LoyaltyCard. LoyaltyCard("Анна") — новая карта: владелец в атрибуте owner, баллов 0,
покупок на 0 ₽. Свойства только для чтения: points — текущие баллы, total — сумма всех покупок.
Метод earn(amount) регистрирует покупку на amount рублей: прибавляет её к сумме покупок, начисляет
баллы — 5 % суммы с округлением вниз — и возвращает число начисленных баллов. Если сумма не больше нуля —
ValueError, и на карте ничего не меняется.
_points и _total; свойства их только возвращают.amount * 5 // 100.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class LoyaltyCard:
def __init__(self, owner):
...
@property
def points(self):
...
@property
def total(self):
...
def earn(self, amount):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class LoyaltyCard:
def __init__(self, owner):
self.owner = owner
self._points = 0
self._total = 0
@property
def points(self):
return self._points
@property
def total(self):
return self._total
def earn(self, amount):
if amount <= 0:
raise ValueError("сумма покупки должна быть больше нуля")
self._total += amount
earned = amount * 5 // 100
self._points += earned
return earnedШаг 2. Уровень и списание
Добавьте в класс (скопируйте его из шага 1 и допишите):
- свойство
level— уровень по сумме покупокtotal: меньше 5000 —"базовый", меньше 20 000 —"серебряный", иначе —"золотой"; - метод
spend(points)— списывает баллы. Еслиpointsне больше нуля —ValueError("списать можно только положительное число баллов"), если баллов на карте меньше —ValueError("недостаточно баллов"); в обоих случаях баланс не меняется.
spend сначала обе проверки с raise, и только потом self._points -= points.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class LoyaltyCard:
# скопируйте сюда __init__, points, total и earn из шага 1
@property
def level(self):
...
def spend(self, points):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class LoyaltyCard:
def __init__(self, owner):
self.owner = owner
self._points = 0
self._total = 0
@property
def points(self):
return self._points
@property
def total(self):
return self._total
@property
def level(self):
if self._total < 5000:
return "базовый"
if self._total < 20000:
return "серебряный"
return "золотой"
def earn(self, amount):
if amount <= 0:
raise ValueError("сумма покупки должна быть больше нуля")
self._total += amount
earned = amount * 5 // 100
self._points += earned
return earned
def spend(self, points):
if points <= 0:
raise ValueError("списать можно только положительное число баллов")
if points > self._points:
raise ValueError("недостаточно баллов")
self._points -= pointsШаг 3. Покупки Анны
Анна сделала за месяц четыре покупки — суммы в списке purchases. Заведите ей карту anna, зарегистрируйте
покупки по порядку и сохраните в earned список начисленных за каждую баллов. В anna_points сохраните её
баллы, в anna_level — уровень карты.
earned = [anna.earn(x) for x in purchases] — метод и регистрирует покупку, и возвращает баллы.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
purchases = [1200, 3500, 800, 900]
anna = ...
earned = ...
anna_points = ...
anna_level = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
purchases = [1200, 3500, 800, 900]
anna = LoyaltyCard("Анна")
earned = [anna.earn(x) for x in purchases]
anna_points = anna.points
anna_level = anna.levelШаг 4. Оплата баллами
Анна хочет оплатить кофе 1000 баллами — у неё столько нет. Попробуйте списать 1000 баллов, перехватите
ValueError и сохраните текст сообщения в error_text. Затем спишите 100 баллов и сохраните остаток
в left.
except ValueError as error: — и error_text = str(error).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
error_text = ...
left = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
try:
anna.spend(1000)
except ValueError as error:
error_text = str(error)
anna.spend(100)
left = anna.pointstry:
anna.points = 1_000_000
except AttributeError as error:
print("не вышло:", error)
print(anna.points)не вышло: property 'points' of 'LoyaltyCard' object has no setter 220
Шаг 5. Золотые клиенты
В словаре clients — имена и суммы покупок каждого клиента за год. Заведите по карте на клиента,
зарегистрируйте все его покупки и сохраните в cards словарь «имя → карта». В gold сохраните список имён
клиентов с золотым уровнем — в порядке словаря.
for name, amounts in clients.items(): — создать карту, в цикле по суммам вызвать earn, положить карту в словарь.gold = [name for name, card in cards.items() if card.level == "золотой"].Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
clients = {
"Анна": [1200, 3500, 800, 900],
"Борис": [15000, 7000],
"Вера": [300, 450],
"Глеб": [9000, 9000, 2500],
}
cards = ...
gold = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
clients = {
"Анна": [1200, 3500, 800, 900],
"Борис": [15000, 7000],
"Вера": [300, 450],
"Глеб": [9000, 9000, 2500],
}
cards = {}
for name, amounts in clients.items():
card = LoyaltyCard(name)
for amount in amounts:
card.earn(amount)
cards[name] = card
gold = [name for name, card in cards.items() if card.level == "золотой"]Итог
for name, card in cards.items():
print(f"{name}: {card.total} ₽, {card.points} баллов, уровень {card.level}")Анна: 6400 ₽, 320 баллов, уровень серебряный Борис: 22000 ₽, 1100 баллов, уровень золотой Вера: 750 ₽, 37 баллов, уровень базовый Глеб: 20500 ₽, 1025 баллов, уровень золотой
У Бориса и Глеба — золотые карты: за год они потратили больше 20 000 ₽. Анна — на серебряном уровне,
Вера — на базовом. И через интерфейс карты баланс не изменить мимо earn и spend: запись в points даёт
AttributeError, а неверные суммы — ValueError с понятным сообщением.
Посмотрите на класс со стороны: снаружи видны только owner, points, total, level, earn и spend.
Как карта хранит данные внутри — её личное дело; можно, например, начать хранить историю покупок списком,
и код снаружи этого не заметит. В следующем модуле объекты научатся красиво печататься и сравниваться.