На складе «Кофейной лавки» — зёрна, молоко, сиропы и стаканы. Утром приходит поставка, днём бариста
расходует запасы, вечером управляющий смотрит, чего осталось мало. Сделаем класс Stock, с которым
всё это пишется так же коротко, как со словарём: len(stock), "Сироп" in stock, stock["Молоко"],
for name in stock, а поставка добавляется оператором +.
Шаг 1. Склад-контейнер
Допишите класс Stock. Stock({"Зёрна": 8, "Молоко": 12}) хранит копию словаря «позиция → количество»
во внутреннем атрибуте _items.
len(stock)— число позиций, у которых количество больше нуля;stock["Молоко"]— количество позиции; если позиции нет — 0 (склад не ругается, а говорит «ноль»);"Молоко" in stock—True, если позиция есть и её количество больше нуля;for name in stock— названия позиций с количеством больше нуля, по алфавиту.
dict(items); количество отсутствующей позиции — метод словаря со значением по умолчанию.__iter__ — генератор по sorted(self._items) с условием на количество.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Stock:
def __init__(self, items):
...
def __len__(self):
...
def __getitem__(self, name):
...
def __contains__(self, name):
...
def __iter__(self):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Stock:
def __init__(self, items):
self._items = dict(items)
def __len__(self):
return len([name for name in self._items if self._items[name] > 0])
def __getitem__(self, name):
return self._items.get(name, 0)
def __contains__(self, name):
return self[name] > 0
def __iter__(self):
for name in sorted(self._items):
if self._items[name] > 0:
yield nameШаг 2. Поставка и расход
Добавьте в класс (скопируйте его из шага 1 целиком):
__add__:stock + supply— новый склад, где количества одинаковых позиций сложены; оба слагаемых не меняются; сложение с чужим типом —NotImplemented;- метод
take(name, amount)— списатьamountединиц позиции; если на складе меньше —ValueError("на складе мало: <название>"), и ничего не меняется.
__add__: начните с dict(self._items) и прибавьте к нему количества из other._items через get(name, 0).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Stock:
# скопируйте сюда методы из шага 1
def __add__(self, other):
...
def take(self, name, amount):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Stock:
def __init__(self, items):
self._items = dict(items)
def __len__(self):
return len([name for name in self._items if self._items[name] > 0])
def __getitem__(self, name):
return self._items.get(name, 0)
def __contains__(self, name):
return self[name] > 0
def __iter__(self):
for name in sorted(self._items):
if self._items[name] > 0:
yield name
def __add__(self, other):
if not isinstance(other, Stock):
return NotImplemented
result = dict(self._items)
for name, amount in other._items.items():
result[name] = result.get(name, 0) + amount
return Stock(result)
def take(self, name, amount):
if self[name] < amount:
raise ValueError(f"на складе мало: {name}")
self._items[name] -= amountШаг 3. Утро
На складе с вечера — leftover, утром пришла поставка delivery. Сохраните в stock склад после поставки,
в n_positions — сколько на нём позиций, а в milk — сколько молока.
__add__; число позиций и молоко — встроенные операции склада.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
leftover = Stock({"Зёрна": 3, "Молоко": 2, "Сироп": 1, "Стаканы": 40, "Сливки": 0})
delivery = Stock({"Зёрна": 5, "Молоко": 10, "Сироп": 2, "Стаканы": 100})
stock = ...
n_positions = ...
milk = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
leftover = Stock({"Зёрна": 3, "Молоко": 2, "Сироп": 1, "Стаканы": 40, "Сливки": 0})
delivery = Stock({"Зёрна": 5, "Молоко": 10, "Сироп": 2, "Стаканы": 100})
stock = leftover + delivery
n_positions = len(stock)
milk = stock["Молоко"]Шаг 4. День
В заготовке склад stock — такой, каким он стал утром после поставки (если выполнить ячейку ещё раз, он
создастся заново). В usage — что бариста взяли со склада за день, по порядку. Спишите всё по очереди методом take;
списания, на которые не хватило запасов, пропускайте, а их названия сохраните в short — в порядке
попыток.
(name, amount) и try: stock.take(name, amount), except ValueError: short.append(name).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
stock = Stock({"Зёрна": 8, "Молоко": 12, "Сироп": 3, "Стаканы": 140, "Сливки": 0}) # склад утром, после поставки
usage = [
("Молоко", 5), ("Стаканы", 60), ("Сироп", 2), ("Зёрна", 3),
("Стаканы", 78), ("Сироп", 2), ("Молоко", 4), ("Сироп", 1),
]
short = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
stock = Stock({"Зёрна": 8, "Молоко": 12, "Сироп": 3, "Стаканы": 140, "Сливки": 0}) # склад утром, после поставки
usage = [
("Молоко", 5), ("Стаканы", 60), ("Сироп", 2), ("Зёрна", 3),
("Стаканы", 78), ("Сироп", 2), ("Молоко", 4), ("Сироп", 1),
]
short = []
for name, amount in usage:
try:
stock.take(name, amount)
except ValueError:
short.append(name)Шаг 5. Вечерний отчёт
Сохраните в low названия позиций, которых осталось меньше 5, — в порядке обхода склада циклом, а в
out_of_syrup — True, если сиропа на складе не осталось.
stock[name]."Сироп" not in stock.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
low = ...
out_of_syrup = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
low = [name for name in stock if stock[name] < 5]
out_of_syrup = "Сироп" not in stockИтог
print(f"позиций: {len(stock)}")
for name in stock:
mark = " ← заказать" if name in low else ""
print(f"{name}: {stock[name]}{mark}")
print("не хватило:", ", ".join(short), "| сироп закончился:", out_of_syrup)позиций: 3 Зёрна: 5 Молоко: 3 ← заказать Стаканы: 2 ← заказать не хватило: Сироп | сироп закончился: True
Утренняя поставка закрыла почти всё, но сиропа хватило ненадолго: 3 бутылки к вечеру ушли полностью, и одно списание не прошло. Мало осталось молока и стаканов — их стоит заказать первыми.
Посмотрите на код шагов 3–5: в нём нет ни одного обращения к _items. Склад ведёт себя как встроенный
контейнер, а как он хранит данные — его внутреннее дело. В последнем модуле перед итоговым проектом появятся
dataclass — способ писать такие классы данных ещё короче.