Модуль 4 · Урок 16 із 58
Comprehensions і вибір структури даних
Comprehension стисло створює нову collection із iterable. Вона корисна, коли transform і filter залишаються очевидними. Якщо в одному виразі з’являються кілька business branches, side effects або незрозуміла nested shape, звичайний loop із named steps буде професійнішим.
Безпечна практика модуля 4
Пакет містить тільки synthetic records, pure collection functions, import-safe CLI і локальні tests. Жодних персональних чи production-даних, secrets, мережевих викликів або зовнішніх залежностей.
Один expression, один transform, один зрозумілий filter
minutes = [15, 60, -1, 75]
valid_minutes = [value for value in minutes if value >= 0]
labels = ["urgent" if value >= 60 else "standard" for value in valid_minutes]List comprehension створює новий list і не має мутувати source. Condition після for фільтрує; conditional expression перед for обирає output value. Їх не можна міняти місцями без зміни сенсу.
Set і dict comprehensions мають collision semantics
normalized_tags = {tag.strip().lower() for tag in raw_tags if tag.strip()}
by_id = {record["id"]: record for record in records}Set comprehension свідомо прибирає duplicates. Dict comprehension може тихо overwrite попередній record з тим самим key. Для identifiers спершу знайдіть duplicates, а вже потім будуйте index; красивий однорядковий вираз не виправдовує втрату evidence.
Nested records: validate, normalize, transform
def normalize_record(record: dict[str, object]) -> dict[str, object]:
case_id = str(record["id"]).strip()
tags = sorted({str(tag).strip().lower() for tag in record.get("tags", []) if str(tag).strip()})
return {**record, "id": case_id, "tags": tags}
normalized = [normalize_record(record) for record in records]Функція повертає новий outer dict, але spread є shallow copy: інші nested values можуть лишитися shared. Контракт має сказати, які fields перебудовані й які references збережені. Недовірений external payload не можна просто cast-ити без schema validation.
Як обрати collection
| Потрібно | Стартовий вибір | Перевірити |
|---|---|---|
| Порядок, повтори, позиції | list | Mutation та boundary indices |
| Фіксована positional shape | tuple | Arity й mutable nested items |
| Key → value | dict | Hashable unique keys і collision policy |
| Унікальність/membership | set | Втрату order та frequency |
Не обирайте structure лише через «швидше». Спочатку correctness contract, розмір і pattern operations; performance твердження перевіряйте вимірюванням на репрезентативних synthetic data.
Коли повернутися до loop
normalized = []
rejected = []
for record in records:
if "id" not in record:
rejected.append({"reason": "missing_id", "record": record})
continue
normalized.append(normalize_record(record))Loop кращий, коли потрібні multiple outputs, reason codes, logging, metrics або кілька guard clauses. Side effect усередині comprehension приховує порядок і ускладнює тест.
Практичний pipeline
- Візьміть synthetic records із лабораторії.
- Не змінюючи input, нормалізуйте ID й tags.
- Знайдіть duplicate IDs до побудови dict index.
- Побудуйте deterministic report із sorted tags і routes.
- Перевірте empty, duplicate, missing field, nested alias і stable output.
- Кожна collection має пояснений contract.
- Comprehension лишається читабельною й без side effects.
- Duplicate/collision evidence не губиться.
- Input mutation перевірена snapshot assertion.
- Output deterministic для однакового synthetic input.
Модуль 4 завершено
Після тесту прогрес становитиме 16/58 уроків і відкриється review-проєкт 1 «CLI utility». Фінальний іспит, PDF, QR та email-сертифікат лишаються заблокованими до всіх 58 уроків і чотирьох прийнятих проєктів.
Методичні джерела
- Python tutorial: List Comprehensions
- Python tutorial: Looping Techniques
- Python built-in types: sequences, mappings and sets
Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть лише на офіційну документацію Python.
Закріпіть матеріал уроку
Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.