Итоговый проект
Представьте кладовщика с тетрадью. На каждой строке тетради — название товара и сколько его лежит на полках. Привезли яблоки — он прибавляет их к строке «яблоки». Просят больше, чем есть, — он отказывает и в тетради ничего не меняет.
Класс в настоящей программе обычно опирается сразу на несколько идей. Например, он хранит данные в словаре, меняет их методами и возбуждает исключение, когда операцию выполнить нельзя. Итоговая задача устроена так же: новых конструкций в ней нет, нужно соединить знакомые.
После неё курс закончен, и следующий шаг — симулятор собеседований по Python. Его открывает кнопка «Пройти собеседование по Python» на странице завершения курса. Симулятор спрашивает и о темах курса, и о тех, которых курс не касался.
Склад
Задача — склад, который считает единицы каждого товара. Тетрадь кладовщика здесь — словарь в классе Inventory:
- ключ — название товара;
- значение — число единиц.
Если забрать товар нельзя, метод take возбуждает исключение OutOfStockError и склад не меняет. Класс OutOfStockError уже объявлен в заготовке, и тесты ловят только его: с другим исключением тест не пройдёт.
| Часть задачи | Что понадобится |
|---|---|
__init__ | атрибут экземпляра со словарём |
add и count | get со значением по умолчанию |
take | сравнение, raise, del |
names | sorted |
Три исхода take
Самый хитрый метод — take: у него три исхода, и тесты проверяют каждый.
- Товара меньше, чем просят, или его нет совсем:
takeвозбуждаетOutOfStockError, и количество не меняется. - Забирают ровно столько, сколько есть: товар исчезает из словаря, и
namesего больше не возвращает. - Товара больше, чем просят: количество уменьшается на
qty.
Здесь аналогия с тетрадью заканчивается. Кладовщик может оставить строку «яблоки — 0». В нашем складе такой строки нет: товар, забранный целиком, удаляют из словаря.
Порядок работы
Работайте по шагам:
- Начните с
__init__: без словаря остальным методам не с чем работать. - Затем пишите по одному методу и после каждого запускайте тесты.
- Почти каждый тест сначала вызывает
add, поэтому ошибка вaddпроваливает сразу много строк. Исправляйте её первой.
Методы заготовки возвращают None, поэтому сначала не проходит ни один из восьми тестов. Строка test_add_then_count показывает got None, а тест, который ждёт исключения, — no OutOfStockError, got None.
Частая ошибка
Словарь объявили атрибутом класса, а не экземпляра:
class Inventory:
items = {} # ✗
def add(self, name, qty):
self.items[name] = self.items.get(name, 0) + qty
def count(self, name):
return self.items.get(name, 0)
shop = Inventory()
home = Inventory()
shop.add("apple", 5)
print(home.count("apple")) # 5Ошибки нет, но склад home видит яблоки, положенные в shop. Давайте разберём, почему:
- Строка
items = {}в теле класса создаёт один словарь — атрибут класса. - У экземпляра
shopсвоего атрибутаitemsнет, поэтомуself.itemsнаходит словарь класса. - Строка
self.items[name] = …присваивает значение ключу этого словаря, а не атрибуту экземпляра. home.count("apple")читает тот же словарь и печатает5.
Атрибут класса один на все экземпляры, и оба склада пишут в одну тетрадь. Каждый тест создаёт свой склад, но с таким атрибутом получает товары из предыдущих тестов. Создайте словарь в __init__: self.items = {}.
На собеседовании часто спрашивают, чем атрибут класса отличается от атрибута экземпляра. Ответ: атрибут класса один на все экземпляры, а атрибут экземпляра у каждого свой, и его создают через self в __init__.
Главное
- Склад хранит количества в словаре: ключ — товар, значение — число единиц.
- Словарь создают в
__init__какself.items = {}, иначе он один на все экземпляры. - При нехватке товара
takeвозбуждаетOutOfStockErrorи склад не меняет. - Товар, забранный целиком, исчезает из словаря и из
names.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.