Поставщик прислал «Кофейной лавке» два прайса — утренний и вечерний. Многие позиции в них повторяются,
а у некоторых за день изменилась цена. Нужно свести прайсы в один без повторов, отсортировать его и найти
товары с новой ценой. Всё это делается магическими методами модуля: __repr__, __eq__, __hash__ и __lt__.
Шаг 1. Товар
Допишите класс Product:
__repr__возвращаетProduct('Латте', 220);- товары равны, если совпадают и название, и цена; сравнение с чужим типом —
NotImplemented; __hash__согласован с__eq__, чтобы товары можно было класть вset.
__eq__: hash((self.name, self.price)).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
...
def __eq__(self, other):
...
def __hash__(self):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return f"Product({self.name!r}, {self.price})"
def __eq__(self, other):
if not isinstance(other, Product):
return NotImplemented
return self.name == other.name and self.price == other.price
def __hash__(self):
return hash((self.name, self.price))Шаг 2. Порядок в прайсе
В уроке о сортировке был совет: если у товаров несколько равноправных порядков, __lt__ не объявляют, а
передают key=. Здесь случай другой: прайс поставщика по договорённости всегда идёт от дешёвого к дорогому,
и этот порядок — естественный для прайса. Поэтому зададим его в классе.
Добавьте в класс (скопируйте его из шага 1 целиком) метод __lt__: товар «меньше», если он дешевле, а при
равной цене — если его название раньше по алфавиту. Сравнение с чужим типом — NotImplemented.
(self.price, self.name) < (other.price, other.name).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Product:
# скопируйте сюда __init__, __repr__, __eq__ и __hash__ из шага 1
def __lt__(self, other):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return f"Product({self.name!r}, {self.price})"
def __eq__(self, other):
if not isinstance(other, Product):
return NotImplemented
return self.name == other.name and self.price == other.price
def __hash__(self):
return hash((self.name, self.price))
def __lt__(self, other):
if not isinstance(other, Product):
return NotImplemented
return (self.price, self.name) < (other.price, other.name)Шаг 3. Два прайса в один
По спискам пар morning и evening создайте товары и сохраните в all_items общий список — сначала утренние,
потом вечерние. В unique сохраните множество (set) товаров без повторов, а в n_dupes — сколько позиций
оказались повторами.
[Product(n, p) for n, p in morning + evening] — оба списка подряд.all_items длиннее unique.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
morning = [("Латте", 220), ("Чай", 120), ("Раф", 260), ("Какао", 190), ("Эспрессо", 150)]
evening = [("Чай", 120), ("Латте", 240), ("Эспрессо", 150), ("Капучино", 220), ("Раф", 260)]
all_items = ...
unique = ...
n_dupes = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
morning = [("Латте", 220), ("Чай", 120), ("Раф", 260), ("Какао", 190), ("Эспрессо", 150)]
evening = [("Чай", 120), ("Латте", 240), ("Эспрессо", 150), ("Капучино", 220), ("Раф", 260)]
all_items = [Product(name, price) for name, price in morning + evening]
unique = set(all_items)
n_dupes = len(all_items) - len(unique)Шаг 4. Прайс по цене
Сохраните в price_list список товаров из unique, отсортированный по естественному порядку товаров
(шаг 2), а в cheapest3 — названия трёх самых дешёвых.
sorted(unique) — set сортируется так же, как список, результат — список.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
price_list = ...
cheapest3 = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
price_list = sorted(unique)
cheapest3 = [p.name for p in price_list[:3]]for p in price_list:
print(p)Product('Чай', 120)
Product('Эспрессо', 150)
Product('Какао', 190)
Product('Капучино', 220)
Product('Латте', 220)
Product('Латте', 240)
Product('Раф', 260)Шаг 5. Что подорожало
Один и тот же товар с разными ценами — это два разных товара для __eq__: в unique остались оба.
Сохраните в alphabet названия всех товаров unique по алфавиту (повторяющиеся названия — подряд), а в
changed — список названий, которые встречаются в unique больше одного раза, то есть товаров, у которых
за день изменилась цена. Каждое название — один раз, по алфавиту.
alphabet = sorted(p.name for p in unique) — порядок по названию задаётся снаружи, __lt__ для этого не нужен.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
alphabet = ...
changed = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
alphabet = sorted(p.name for p in unique)
counts = {}
for name in alphabet:
counts[name] = counts.get(name, 0) + 1
changed = [name for name, n in counts.items() if n > 1]Итог
print(f"позиций в двух прайсах: {len(all_items)}, повторов: {n_dupes}")
print("сводный прайс:", price_list)
for name in changed:
prices = sorted(p.price for p in unique if p.name == name)
print(f"изменилась цена: {name}, цены в прайсах {prices}")позиций в двух прайсах: 10, повторов: 3
сводный прайс: [Product('Чай', 120), Product('Эспрессо', 150), Product('Какао', 190), Product('Капучино', 220), Product('Латте', 220), Product('Латте', 240), Product('Раф', 260)]
изменилась цена: Латте, цены в прайсах [220, 240]Из десяти позиций двух прайсов три оказались повторами, в сводном прайсе семь товаров. Цена за день
изменилась только у латте: утром 220 ₽, вечером 240 ₽. Заметьте, как удобно смотреть на такие списки, когда
у товара есть __repr__: print(price_list) сразу показывает и названия, и цены.
В проекте два порядка: естественный порядок прайса (по цене) задан в классе, а порядок по алфавиту — снаружи,
ключом. Если бы ни один порядок не был главным, честнее было бы обойтись одним key=, как советует урок
о сортировке. В следующем модуле появятся иерархии
классов: разные виды скидок, которые касса применяет одинаково.