Урок 18. Узагальнення модуля 1 і фінальний проєкт¶
Модуль 1 мав дві історії. Кафе «Смачно»: від змінних з сумою чека (урок 3) до звіту з функцій (урок 8), модулів і командного рядка (урок 13), винятків (урок 14), файлів і JSON (урок 15) та командного проєкту на GitHub (урок 16). Диспетчерська таксі: три практикуми про ціну рішення (урок 9), вибір стратегії пошуку (урок 12) і хеш-структури (урок 17).
А тепер згадай весну 2020-го. Карантин: зали кафе зачинені, гостей немає. Таксі стоять: пасажирів теж немає. І водночас — бум доставки: люди сидять удома й замовляють їжу, а бізнес, який швидко переналаштувався, вижив. Кафе «Смачно» і диспетчерська таксі домовляються: кафе готує, водії таксі розвозять. За кілька тижнів доставка стає головним джерелом виторгу для обох.
Але облік у них різний: у кафе — рядки каси, у таксі — журнал поїздок. Потрібна одна система, яка знає і про чеки, і про доставки. Це фінальний проєкт модуля: ти збереш його сам, за день чи два, і в ньому знадобиться майже все, що було в модулі.
Що потрібно: уроки 1–17.
Після уроку ти зможеш:
- пояснити, як теми модуля пов'язані між собою і навіщо кожна з них знадобилась;
- проєктувати програму зверху вниз: задача → дані → стан → операції → перетворення → модулі → код;
- зібрати консольну систему з шести модулів, яка зберігає стан у JSON, пояснює помилки людською мовою і перевіряється тестами;
- вести проєкт у власному репозиторії: гілки, коміти, Pull Request, README.
Задача розділу. Фінальний проєкт «Смачно + Таксі» у теці capstone/.
Ноутбук заняття: Відкрити вправи в Colab Переглянути розв’язки
Карта модуля¶
flowchart TD
classDef step fill:#eceff1,stroke:#546e7a,stroke-width:1px,color:#1a1a1a;
classDef decision fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,color:#1a1a1a;
classDef success fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1a1a1a;
classDef error fill:#ffebee,stroke:#c62828,stroke-width:3px,color:#1a1a1a;
classDef warning fill:#fff8e1,stroke:#e65100,stroke-width:2px,color:#1a1a1a;
A["основа · уроки 1–4<br>середовище, типи, умови"] --> B["дані · уроки 5–6<br>list, tuple, set, dict"]
B --> C["функції · уроки 8, 10, 11<br>return, декоратори, генератори"]
C --> D["система · уроки 13–16<br>модулі, винятки, файли, Git"]
B --> E["алгоритми · уроки 9, 12, 17<br>Big O, пошук, хешування"]
D --> F["фінальний проєкт<br>Смачно + Таксі"]
E --> F
class A,B,C,D,E step
class F success
| Урок | Що дав | Де знадобиться в проєкті |
|---|---|---|
| 3–4 | типи, перетворення, умови | float("540.00"), перевірки сум і кількості гостей |
| 5–6 | NamedTuple, списки, словники |
Order, Delivery, лічильники |
| 7 | функції з контрактом | кожна частина — набір маленьких функцій |
| 8, 11, 16 | Big O, пошук, dict / set / Counter |
пошук замовлення за номером, райони, ваучер |
| 12 | модулі, datetime, sys.argv |
шість файлів, дати, команди з термінала |
| 13 | винятки, raise |
зрозумілі помилки замість трасувань |
| 14 | with open, JSON |
стан у data.json між запусками |
| 15 | Git, гілки, PR, тести | власний репозиторій, check.py |
Десять ідей модуля¶
Коротко — те, що варто пам'ятати й через рік:
- Змінна — ярлик, а не коробка (урок 3).
b = aдля списку — два ярлики на один об'єкт. - Python динамічний, але строгий (урок 3).
"Чек: " + 540—TypeError: перетворюй явно. - Структура даних визначає алгоритм (уроки 9, 12, 17). Той самий пошук —
O(n)у списку,O(log n)у відсортованому,O(1)у словнику. - Функція — рівень абстракції (урок 8).
print_report(orders)читається як крок, а не як 30 рядків. - Чиста функція передбачувана (урок 8). Той самий вхід — той самий результат, без змін чужих даних.
- Помилки — це нормально, якщо їх обробляти (урок 14). Ловити там, де знаєш, що відповісти людині, і ніколи не мовчки.
- Дані живуть поза програмою (урок 15). Змінні зникають, файли лишаються.
- Стандартна бібліотека — перший ресурс (урок 13).
datetime,collections,json,csv— уже встановлені. - Git — спосіб мислення (урок 16). Маленькі осмислені кроки, історія, гілки, рев'ю.
- Середовище — фундамент (урок 2). Активуй середовище → встанови → запускай.
Перевір себе: прогнози¶
Спершу скажи, що надрукує кожен фрагмент, потім розгорни відповідь. У ноутбуці заняття ці самі прогнози можна запустити.
1. Урок 3:
2. Урок 4:
3. Урок 6:
4. Урок 8:
def add_order(bill, orders=[]):
orders.append(bill)
return orders
add_order(540)
print(add_order(320))
5. Урок 11:
6. Урок 14:
7. Урок 15:
8. Урок 17:
Відповіді
[540, 320, 980]—aіb— ярлики одного списку.True False False— непорожній рядок істинний, навіть"0"; нуль і порожній список — хибні.{'пт': 2, 'сб': 1}.[540, 320]— список за замовчуванням створюється один раз, при оголошенні функції. Правильно:orders=Noneіif orders is None: orders = [].[200, 400] []— генератор вичерпується після першого проходу.A, потімC:elseлише без винятку,finally— завжди.{'7': ['пт', 540]}— ключ став рядком, кортеж — списком.TypeError: unhashable type: 'list'— ключ має бути незмінним; маршрут — кортежем.
Чекліст модуля 1: чи можу я пояснити…
- різницю між інтерпретатором,
pip,venvі IDE; навіщо активувати середовище; - чим
int,float,str,boolвідрізняються і як їх перетворювати; чому0.1 + 0.2 != 0.3; - порядок
if/elif/elseі колиwhileзупиняється; - коли брати
list,tuple,set,dict; як розпакувати кортеж; returnпротиprint; значення за замовчуванням; область видимості;- що робить декоратор і
functools.wraps; чим генератор відрізняється від списку; - що таке
O(1),O(log n),O(n),O(n²)і як їх упізнати в коді; - що робить
import; навіщоif __name__ == "__main__":; try/except/else/finally,raise, чому не можна голийexcept:;with open(...), режимиr/w/a,json.dump/json.load;git add/commit/push, гілка, Pull Request, конфлікт.
Якщо якийсь пункт не пояснюється — повернися до уроку з карти вище, перш ніж братися за проєкт.
Фінальний проєкт: Смачно + Таксі¶
Доставка на карантині працює так. Каса кафе, як і раніше, дає замовлення рядками. Адміністратор додає до замовлення доставку: район, вартість, водія. Власниця хоче спільний звіт: скільки замовлень, скільки з них доставлено, виторг кафе й таксі, найкращий день, популярні райони — куди варто відправити більше водіїв. А служба підтримки — знайти пару доставок під ваучер.
Великі програми не пишуть «з першого рядка коду». Їх проєктують зверху вниз, і лише потім пишуть код. Пройдемо ці кроки для нашої системи.
1. Задача — одним реченням¶
Консольна програма, яка зберігає замовлення кафе й доставки таксі між запусками і відповідає на питання власниці, адміністратора й служби підтримки.
2. Дані — які записи існують¶
| Запис | Поля | Звідки взявся |
|---|---|---|
Order |
id, time (datetime), bill, tip, guests |
каса, уроки 14–15 |
Delivery |
order_id, district, fare, driver |
таксі, уроки 9, 12, 17 |
Зв'язок між ними — Delivery.order_id: номер замовлення, яке доставляють. У кожного замовлення щонайбільше одна доставка.
3. Стан — що треба пам'ятати між запусками¶
Два списки, orders і deliveries. Між запусками вони живуть у data.json (урок 15): кожна команда спершу читає стан, потім, якщо щось змінила, записує його назад. Перший запуск — файлу ще немає, стан порожній.
4. Операції — що вміє система¶
| Команда | Що робить | Змінює стан? |
|---|---|---|
import ФАЙЛ |
усі правильні рядки каси — у замовлення, про зіпсовані пояснення | так |
add-order "РЯДОК" |
одне замовлення в тому самому форматі | так |
add-delivery НОМЕР РАЙОН ВАРТІСТЬ ВОДІЙ |
доставка існуючого замовлення | так |
find НОМЕР |
замовлення та його доставка | ні |
report |
спільний звіт кафе й таксі | ні |
voucher СУМА |
дві доставки на суму ваучера | ні |
5. Перетворення — як дані змінюють форму¶
рядок каси "2024-07-19 18:30;540.00;50;2" → parse_order → Order
аргументи ["1", "Оболонь", "230", "D-3"] → parse_delivery → Delivery
Order / Delivery → save_state → JSON → load_state → Order / Delivery
orders + deliveries → cafe_stats, taxi-функції → текст звіту
Будь-які неправильні дані зупиняються на вході й перетворюються на ValueError з поясненням (урок 14). Далі в системі живуть лише правильні Order і Delivery.
6. Модулі — як розділити систему¶
flowchart TD
classDef step fill:#eceff1,stroke:#546e7a,stroke-width:1px,color:#1a1a1a;
classDef decision fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,color:#1a1a1a;
classDef success fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1a1a1a;
classDef error fill:#ffebee,stroke:#c62828,stroke-width:3px,color:#1a1a1a;
classDef warning fill:#fff8e1,stroke:#e65100,stroke-width:2px,color:#1a1a1a;
APP["app.py<br>команди з термінала"] --> CMD["6. commands.py<br>зв'язує кафе і таксі"]
APP --> ST["3. storage.py<br>data.json"]
CMD --> PR["2. parsing.py<br>перевірка входу"]
CMD --> CAFE["4. cafe.py<br>статистика кафе"]
CMD --> TAXI["5. taxi.py<br>індекс, райони, ваучер"]
CAFE --> RU["1. rules.py<br>день і прийом їжі"]
CMD --> RU
PR --> MOD["models.py<br>Order, Delivery"]
ST --> MOD
class APP,MOD warning
class CMD success
class ST,PR,CAFE,TAXI,RU step
Помаранчеві модулі дає викладач: models.py з двома записами і app.py, який розбирає sys.argv, читає й записує стан, ловить ValueError і друкує Помилка: …. Шість сірих і зелений — твої. Контракт кожної функції — у її докстрінгу, як у командному проєкті уроку 16.
| № | Файл | Функції | Урок |
|---|---|---|---|
| 1 | rules.py |
meal_type, day_name |
12 |
| 2 | parsing.py |
parse_order, parse_delivery |
13 |
| 3 | storage.py |
save_state, load_state |
14 |
| 4 | cafe.py |
cafe_stats |
6, 7, 12 |
| 5 | taxi.py |
delivery_index, top_districts, voucher_pair |
11, 16 |
| 6 | commands.py |
add_order, import_kasa, add_delivery, find_order, report, voucher |
7, 13 |
commands.py — місце, де кафе і таксі стають однією системою. Наприклад, add_delivery перевіряє, що замовлення існує (множина номерів, урок 17) і ще не має доставки (словник-індекс), і лише потім додає доставку.
7. Код — і як перевірити¶
Коли все зроблено, сесія адміністратора виглядає так (справжній вивід еталонного розв'язку):
Імпортовано: 4, пропущено: 5
рядок 3: could not convert string to float: '540,00'
рядок 5: очікували 4 поля, а маємо 2
рядок 6: day is out of range for month
рядок 7: сума чека має бути більшою за 0, а маємо -120.0
рядок 8: гостей має бути хоча б один, а маємо 0
python app.py add-delivery 1 Оболонь 230 D-3
python app.py add-delivery 2 Поділ 180 D-1
python app.py add-delivery 3 Оболонь 270 D-3
python app.py add-delivery 3 Печерськ 150 D-2
Доставка №1: Оболонь, 230 грн, водій D-3
Доставка №2: Поділ, 180 грн, водій D-1
Доставка №3: Оболонь, 270 грн, водій D-3
Помилка: замовлення №3 вже має доставку
№3 2024-07-20 20:15, 980.00 грн, гостей: 4, доставка: Оболонь (270 грн)
Помилка: номер замовлення має бути цілим числом, а маємо три
Замовлень: 4, з доставкою: 3
Кафе: 3040.00 грн, середній чек 760.00 грн, найкращий день: нд
Таксі: 680 грн за доставки
Райони: Оболонь 2, Поділ 1
Разом: 3720.00 грн
Ваучер 500 грн: доставки замовлень №1 і №3
Кожна команда — окремий запуск програми, але report бачить доставки, додані раніше: стан пережив завершення програми в data.json.
Перевірка — check.py, як в уроці 16:
python check.py # таблиця: яка частина готова
python check.py 2 # тести частини 2
python check.py all # усі частини + ця сесія адміністратора
Частини роби по порядку: 4 використовує 1, а 6 — майже все. Якщо тест частини 6 пише ще не зроблено — частина 2: напиши parse_order(), спершу допиши частину 2.
Як здавати¶
- Власний публічний репозиторій на GitHub (інструкція), у ньому вміст теки
capstone/безsolution/. - Кожна частина — окрема гілка
part-N-…, осмислені коміти, Pull Request у свійmain, злиття. Так історія покаже, як система росла. README.mdтвого репозиторію: що вміє система, як запустити, приклад виводуreport.- Посилання на репозиторій — викладачеві.
Можна командою, як в уроці 16: шість частин — шість людей, контракти ті самі.
Критерії оцінювання:
| Критерій | Як перевіряється |
|---|---|
| система працює | python check.py all → ✅ Система працює! |
| помилки пояснені | неправильні команди дають Помилка: …, а не трасування |
| стан зберігається | data.json після перезапуску; data.json — у .gitignore |
| історія | гілка й PR на кожну частину, зрозумілі повідомлення комітів |
| README | опис, запуск, приклад виводу |
Для охочих — розширення, яких немає в тестах:
- команда
list— усі замовлення в таблиці через f-string з вирівнюванням (урок 3); drivers— виторг кожного водія, від більшого до меншого (Counter);export report.json— звіт у JSON для сайту кафе (урок 15);- доставки за датою:
report 2024-07-20— лише замовлення цього дня.
Підсумок¶
| Крок проєктування | Питання | У проєкті |
|---|---|---|
| Задача | що і для кого? | система доставки для кафе й таксі |
| Дані | які записи? | Order, Delivery |
| Стан | що пам'ятати? | два списки в data.json |
| Операції | що вміє? | шість команд |
| Перетворення | як дані змінюють форму? | рядок → запис → JSON → звіт |
| Модулі | як розділити? | шість модулів з контрактами |
| Код і перевірка | чи працює? | check.py all, Git, README |
Що далі¶
- Ноутбук заняття: Відкрити вправи в Colab Переглянути розв’язки — прогнози з усього модуля і запуск фінального проєкту в Colab.
- Довідник:
notes_module1_review.ipynb— докладний конспект усього модуля: велика картина, ментальна модель Python, чекліст. Нумерація уроків у ньому не збігається з нумерацією книги.
- Модуль 2 починається з уроку 19 «Функції як об'єкти першого класу»: функції, які приймають і повертають функції — те, що вже трапилося в декораторах уроку 10, стане основним інструментом.
Документація і джерела¶
- Python Tutorial — повторення модуля одним читанням: An Informal Introduction → Data Structures → Modules → Errors and Exceptions → Input and Output
typing.NamedTuple,json,sys.argv- Для охочих: Harvard CS50P, фінальний проєкт — вимоги до власного проєкту в тому самому дусі: задача, код, тести, README.