Заведи для цього завдання окрему теку — хай буде dz18/ — і працюй у ній.
Скрізь, де просять «навмисно зламати», зберігай повний traceback текстом:
він і є доказом того, що ти зробив.
рівень 1Рівень 1 — База
Напиши файл kalkulyator.py з функцією podilyty(a, b), яка повертає a / b.
- Обгорни ділення в
try/exceptіз конкретним типом: при діленні на нуль функція має повертати рядок"на нуль ділити не можна", а не падати. - Додай другу гілку
except TypeError, яка повертає"аргументи мають бути числами"— вона спрацює, якщо передати рядок. - Додай блок
finally, який дописує+1до глобального лічильникавикликів. - У кінці файлу, під
if __name__ == "__main__":, постав перевірки:
python
assert podilyty(10, 2) == 5.0
assert podilyty(10, 0) == "на нуль ділити не можна"
assert podilyty("десять", 2) == "аргументи мають бути числами"
assert викликів == 3, "finally мав спрацювати на кожен виклик"
print("✅ рівень 1")
Зроблено, якщо: python3 kalkulyator.py друкує ✅ рівень 1 і більше нічого;
у файлі немає жодного голого except: і жодного except Exception.
рівень 2Рівень 2 — Плюс
Візьми битий прайс і доведи на числах, чим голий except шкідливий.
- Створи файл
prays.txtіз шістьма рядками форматуназва;ціна, з яких три зіпсовані по-різному: ціна словами, немає крапки з комою, порожня назва. (Читати файл ще не вчились — просто поклади ті самі рядки в список у коді, аprays.txtхай буде довідкою для тебе.) - Напиши два варіанти обробника прайсу в одному файлі
porivnyannya.py: rozibraty_goliy(ryadok)— зexcept:без типу;rozibraty_tochno(ryadok)— зexcept (ValueError, IndexError).- Тепер зроби в обох функціях однаковий одрук: напиши
flotзамістьfloat. Запусти обидві на всьому прайсі й запиши вsposterezhennya.md: - що надрукувала кожна версія;
- яку суму дала кожна;
- traceback, який показала точна версія.
- Поверни
floatна місце й переконайся, що тепер обидві версії дають однакову суму. Додайassert, який це фіксує.
Зроблено, якщо: у sposterezhennya.md є (а) дві різні суми з одруком,
(б) traceback зі словом NameError, (в) абзац своїми словами про те, чому
різниця в одному слові після except коштує стільки; а python3 porivnyannya.py
у виправленій версії відпрацьовує без помилок і друкує пройдений assert.
рівень 3Рівень 3 — Виклик
Побудуй власну ієрархію винятків і доведи, що вона поводиться як дерево.
- У файлі
vynyatky.pyопиши три типи:
PomylkaPraysu(Exception)
├── PomylkaCiny — ціна не число або відʼємна
└── PomylkaFormatu — рядок не розкладається рівно на дві частини
- У файлі
rozbir.pyнапишиrozibraty(ryadok), яка кидає точний підтип у кожному випадку й обовʼязково зберігає первинну причину черезfrom e. - Доведи
assert-ами всі чотири твердження: except PomylkaCinyловить помилку ціни й не ловить помилку формату;except PomylkaPraysuловить обидві;except Exceptionтеж ловить обидві;except KeyboardInterruptне ловить жодної.- Заміряй довжину traceback у рядках для трьох варіантів підняття на одному й тому
самому зіпсованому рядку:
raise X(...),raise X(...) from e,raise X(...) from None. Підказка:traceback.format_exc()повертає звіт рядком. Запиши три числа вtracebacks.mdі поясни, чому два з них однакові, а третє менше. - Додай у
rozbir.pyфункціюobrobyty(ryadky), яка повертає три списки:ciny,skargy(очікуваніPomylkaPraysu) іavarii(усе інше). Перевір її на списку, де один елемент — не рядок, а число42, і доведиassert-ом, що це число опинилось саме вavarii.
Зроблено, якщо: python3 rozbir.py відпрацьовує без помилок; усі assert
з пунктів 3 і 5 мовчать; у tracebacks.md є три числа й абзац пояснення,
у якому названо, що саме додає до звіту неявний ланцюжок.
Підказки
- Не вгадуй тип винятку — спитай. Обгорни підозрілий рядок у
try: ... except BaseException as e: print(type(e).__name__, e). Це разова діагностика, а не код, який лишається: дізнався тип — заміни на конкретний. float("28.5")іfloat(None)падають по-різному. Перший даєValueError(рядок є, але не схожий на число), другий —TypeError(рядка немає взагалі). У завданні другого рівня це пригодиться.- Щоб
finallyбуло видно, друкуй у ньому рядок або дописуй у список. Інакше легко переконати себе, що він виконався, не перевіривши цього. - Власний виняток успадковуй від
Exception, не відBaseException. Інакше твоя біда поведеться як Ctrl+C і проскочить повз усі чужі обробники. - Якщо
assertмовчить — це успіх. Він друкує щось лише тоді, коли все погано. Тому наприкінці ставлятьprint("✅ …"): інакше не видно, що перевірка взагалі була. - Файли
__pycache__у роботу не здаються.