Модуль 4 · Урок 14 із 58
Словники: ключі, безпечний доступ і schema
Dictionary пов’язує унікальний key із value. Це зручно, але не робить дані автоматично структурованими: треба визначити дозволені keys, required fields, типи values, duplicate policy і різницю між «поля немає» та «значення поля — None».
Безпечна практика модуля 4
Пакет містить тільки synthetic records, pure collection functions, import-safe CLI і локальні tests. Жодних персональних чи production-даних, secrets, мережевих викликів або зовнішніх залежностей.
Mapping contract
Для record у dict запишіть schema до коду: required keys, optional keys, тип кожного value, unknown-key policy та normalization boundary. Dict із довільними keys — гнучкий лише до першої помилки в написанні, яка тихо створить нове поле.
case = {
"id": "case-17",
"route": "urgent",
"minutes": 75,
"tags": ["priority", "synthetic"],
}id, route і minutes required; tags optional list[str]; unknown keys rejected at boundary.Keys мають бути hashable й унікальні
String, number або tuple з hashable items може бути key. List чи dict не може, бо його equality-relevant state змінюється. Якщо записати те саме key вдруге, попереднє value буде замінено — це не duplicate history.
index = {"case-17": "review"}
index["case-17"] = "urgent"
print(index) # {"case-17": "urgent"}Тому під час побудови index duplicate IDs треба ловити до assignment, якщо overwrite не є свідомою policy.
[] і get відповідають на різні питання
# required: відсутність є помилкою schema
case_id = case["id"]
# optional: відсутність має documented default
tags = case.get("tags", [])Subscript піднімає KeyError і добре сигналізує порушення required contract. get доречний для optional field. Але case.get("owner") не відрізняє missing від explicit None; коли різниця важлива, перевіряйте "owner" in case або використовуйте окремий sentinel.
Iteration має називати те, що читає
for key in case:
print(key)
for key, value in case.items():
print(key, value)Iteration по dict за замовчуванням дає keys. keys(), values() і items() повертають dynamic views, а не frozen snapshots. Dict зберігає insertion order, але sorted business output треба створювати явно: for key in sorted(case).
Merge потребує collision policy
defaults = {"route": "standard", "tags": []}
incoming = {"route": "urgent", "id": "case-17"}
merged = {**defaults, **incoming} # right side winsRight-wins синтаксис короткий, але не відповідає, чи caller мав право змінити route. Для конфігів, permissions і identifiers collisions треба перевіряти й документувати. setdefault теж mutation; не ховайте його всередині read-only validation.
Вкладені dict не замінюють validation
Ланцюжок payload["user"]["profile"]["name"] має кілька окремих failure points і нічого не каже про types. Розбийте boundary validation на маленькі checks, поверніть нормалізований record і тільки потім виконуйте business logic.
- Required/optional/unknown fields визначені.
- Duplicate keys та merge collisions мають policy.
- Missing не змішується з explicit None.
- Output order створюється свідомо.
- Caller-owned nested values не мутуються під час validation.
Методичні джерела
- Python tutorial: Dictionaries
- Python built-in types: Mapping Types
- Python glossary: dictionary views and hashable
Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть лише на офіційну документацію Python.
Закріпіть матеріал уроку
Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.