Касса «Кофейной лавки» собирает заказ в корзину: бариста добавляет товары, покупатель передумывает и
что-то убирает, а в конце касса считает сумму. Корзина — объект, который хранит другие объекты, товары.
В проекте пригодится всё из модуля: свой список у каждого экземпляра, ссылки на объекты и is.
Что у нас уже есть
Товар — уже знакомый класс с названием и ценой:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
latte = Product("Латте", 220)
print(latte.name, latte.price)Латте 220
Шаг 1. Корзина
Допишите класс Cart. У новой корзины — пустой список items, свой у каждой корзины. Метод add(product)
кладёт товар в корзину, метод total() возвращает сумму цен всех товаров (у пустой корзины — 0).
self.items = [] — в __init__; add — self.items.append(product).total — сумма p.price по всем товарам: циклом или sum(p.price for p in self.items).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Cart:
def __init__(self):
...
def add(self, product):
...
def total(self):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Cart:
def __init__(self):
self.items = []
def add(self, product):
self.items.append(product)
def total(self):
return sum(p.price for p in self.items)Шаг 2. Убрать и найти
Добавьте в класс два метода — скопируйте класс из шага 1 целиком и допишите их:
remove(name)убирает из корзины первый товар с таким названием и возвращаетTrue; если такого товара нет — ничего не меняет и возвращаетFalse;most_expensive()возвращает самый дорогой товар корзины (сам объект), а у пустой корзины —None.
remove: цикл по self.items; нашли товар — self.items.remove(p) и сразу return True. После цикла — return False.most_expensive: если список пуст — return None; иначе запомните первый товар и сравнивайте с ним остальные по цене.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Cart:
# скопируйте сюда __init__, add и total из шага 1
def remove(self, name):
...
def most_expensive(self):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Cart:
def __init__(self):
self.items = []
def add(self, product):
self.items.append(product)
def total(self):
return sum(p.price for p in self.items)
def remove(self, name):
for p in self.items:
if p.name == name:
self.items.remove(p)
return True
return False
def most_expensive(self):
if not self.items:
return None
best = self.items[0]
for p in self.items:
if p.price > best.price:
best = p
return bestШаг 3. Две корзины
Создайте две корзины: anna — с латте и круассаном, boris — с чаем и латте. Латте — один и тот же
товар latte из заготовки: в меню он один. Сохраните суммы корзин в anna_total и boris_total.
anna = Cart(), затем anna.add(latte) и anna.add(croissant); так же для boris.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
latte = Product("Латте", 220)
croissant = Product("Круассан", 140)
tea = Product("Чай", 120)
anna = ...
boris = ...
anna_total = ...
boris_total = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
latte = Product("Латте", 220)
croissant = Product("Круассан", 140)
tea = Product("Чай", 120)
anna = Cart()
anna.add(latte)
anna.add(croissant)
boris = Cart()
boris.add(tea)
boris.add(latte)
anna_total = anna.total()
boris_total = boris.total()Шаг 4. Цена изменилась
Пока покупатели стоят в очереди, кофейня поднимает цену латте до 250 ₽.
Измените цену товара latte на 250 и сохраните новые суммы корзин в anna_new и boris_new. Товары
в корзины заново не добавляйте.
latte.price = 250: в обеих корзинах лежит этот же объект.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
anna_new = ...
boris_new = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
latte.price = 250
anna_new = anna.total()
boris_new = boris.total()Шаг 5. Борис передумал
Борис передумал: уберите из его корзины чай и добавьте раф raf. Результат remove для чая сохраните
в removed, а в missing — результат попытки убрать какао, которого в корзине нет. Самый дорогой товар
корзины Бориса после замены сохраните в boris_top.
removed = boris.remove("Чай"), missing = boris.remove("Какао"), затем boris.add(raf) и boris_top = boris.most_expensive().Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
raf = Product("Раф", 260)
removed = ...
missing = ...
boris_top = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
raf = Product("Раф", 260)
removed = boris.remove("Чай")
missing = boris.remove("Какао")
boris.add(raf)
boris_top = boris.most_expensive()Итог
for name, cart in [("Анна", anna), ("Борис", boris)]:
names = ", ".join(p.name for p in cart.items)
print(f"{name}: {names} — {cart.total()} ₽")
print("латте в обеих корзинах — один объект:", anna.items[0] is boris.items[0])Анна: Латте, Круассан — 390 ₽ Борис: Латте, Раф — 510 ₽ латте в обеих корзинах — один объект: True
Цена латте поменялась один раз — и сразу в обеих корзинах: корзины хранят не копии товаров, а ссылки на один
объект latte. В кассе это удобно (новая цена видна везде), но значит и обратное: изменить товар «только для
одной корзины» нельзя — для этого нужен отдельный объект.
Корзина — первый пример композиции (composition): объект хранит другие объекты и работает с ними через их атрибуты и методы. Подробно о композиции — в модуле 6. А в следующем модуле научимся защищать состояние объекта: чтобы цену нельзя было случайно сделать отрицательной.