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

Итоговый проект: каталог и корзина

Первая часть кассы «Кофейной лавки»: свои исключения, товар-dataclass, каталог-контейнер, загрузка каталога из строк и корзина, которая берёт товары из каталога.

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

В итоговом проекте вы соберёте кассу «Кофейной лавки» целиком — из классов, которые писали по отдельности весь курс. Проект в двух уроках. В этом — модель: товары, каталог и корзина. В следующем — правила: скидки, оплата, чек и отчёт за день.

Почти всё здесь вы уже делали; новое — в том, чтобы решить, какой инструмент взять для каждой части:

Часть кассы Что это Инструмент
ошибки своя иерархия подклассы Exception
товар неизменяемые данные @dataclass(frozen=True)
каталог контейнер товаров __len__, __contains__, __getitem__, __iter__
корзина содержит каталог и строки композиция, свойство, магические методы

Шаг 1. Ошибки кассы

[ ]Упражнение 1ShopError и UnknownProductError решено

Объявите базовое исключение кассы ShopError (подкласс Exception) и его подкласс UnknownProductError — «товара нет в каталоге».

# объявите ShopError и UnknownProductError

Шаг 2. Товар

[ ]Упражнение 2Product решено

Объявите неизменяемый dataclass Product с полями name (строка), price (целое) и category (строка, например "кофе"). Цена не больше нуля — ValueError при создании. str(product) — "Латте — 220 ₽".

from dataclasses import dataclass, field


class Product:
    ...

Шаг 3. Каталог

[ ]Упражнение 3Catalog решено

Объявите класс Catalog: Catalog([товар, товар, …]) хранит товары во внутреннем словаре «название → товар».

  • len(catalog) — число товаров;
  • "Латте" in catalog — есть ли товар с таким названием;
  • catalog["Латте"] — товар; если его нет — UnknownProductError("нет в каталоге: Латте");
  • for product in catalog — товары по алфавиту названий.
class Catalog:
    def __init__(self, products):
        ...

    def __len__(self):
        ...

    def __contains__(self, name):
        ...

    def __getitem__(self, name):
        ...

    def __iter__(self):
        ...

Шаг 4. Каталог из строк

[ ]Упражнение 4Загрузка каталога решено

Напишите функцию load_catalog(lines): из строк вида "Латте;220;кофе" она собирает Catalog. Затем загрузите каталог кофейни из menu_lines в переменную catalog.

def load_catalog(lines):
    ...


menu_lines = [
    "Эспрессо;150;кофе", "Капучино;220;кофе", "Латте;240;кофе", "Раф;260;кофе",
    "Чай;120;чай", "Какао;190;другое", "Круассан;140;выпечка", "Маффин;130;выпечка",
]
catalog = ...

[ ]Каталог по алфавиту
for product in catalog:
    print(f"{product} ({product.category})")
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
Какао — 190 ₽ (другое)
Капучино — 220 ₽ (кофе)
Круассан — 140 ₽ (выпечка)
Латте — 240 ₽ (кофе)
Маффин — 130 ₽ (выпечка)
Раф — 260 ₽ (кофе)
Чай — 120 ₽ (чай)
Эспрессо — 150 ₽ (кофе)
Вывод появится, когда решите упражнение «Загрузка каталога», — иначе он подскажет ответ. Ячейку можно и выполнить.

Шаг 5. Корзина

Строка корзины — товар и количество. Это маленький dataclass, он уже готов:

[ ]Строка корзины
from dataclasses import dataclass


@dataclass
class Line:
    product: Product
    qty: int

    @property
    def cost(self):
        return self.product.price * self.qty


print(Line(catalog["Латте"], 2), Line(catalog["Латте"], 2).cost)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
Line(product=Product(name='Латте', price=240, category='кофе'), qty=2) 480
[ ]Упражнение 5Cart решено

Объявите класс Cart: Cart(catalog) — пустая корзина, которая содержит каталог и берёт товары из него.

  • add(name, qty=1) — найти товар в каталоге (неизвестный — UnknownProductError уходит дальше) и добавить строку; если строка с этим товаром уже есть — увеличить её количество, а не добавлять вторую;
  • len(cart) — число строк, for line in cart — строки по порядку добавления;
  • свойство subtotal — сумма cost всех строк.
class Cart:
    def __init__(self, catalog):
        ...

    def add(self, name, qty=1):
        ...

    def __len__(self):
        ...

    def __iter__(self):
        ...

    @property
    def subtotal(self):
        ...

Шаг 6. Первые заказы

[ ]Упражнение 6Три корзины решено

По списку requests — что попросил каждый покупатель — соберите корзины. Сохраните в subtotals суммы корзин по порядку, а в unknown — названия, которых нет в каталоге (такие позиции пропускайте, остальное в корзину кладите).

requests = [
    [("Латте", 2), ("Круассан", 2), ("Латте", 1)],
    [("Капучино", 1), ("Глинтвейн", 1), ("Чай", 2), ("Маффин", 1)],
    [("Раф", 1), ("Какао", 1)],
]
subtotals = ...
unknown = ...

Итог

[ ]Корзины
print(f"в каталоге {len(catalog)} товаров")
for i, total in enumerate(subtotals, 1):
    print(f"корзина {i}: {total} ₽")
print("нет в каталоге:", ", ".join(unknown))
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
в каталоге 8 товаров
корзина 1: 1000 ₽
корзина 2: 590 ₽
корзина 3: 450 ₽
нет в каталоге: Глинтвейн
Итог появится, когда решите все упражнения урока, — в нём ответы. Ячейку можно и выполнить.

Модель кассы готова: каталог из восьми товаров, три корзины на 1000, 590 и 450 ₽, а «Глинтвейна» в каталоге нет — касса не упала, а сообщила об этом исключением. В следующем уроке к этой модели добавятся скидки, оплата и чек.

Выводы с ответами появятся, когда решите все упражнения урока.
Нашли ошибку?