k07. Файлы, JSON, CSV, YAML
UAV Python Pro · Конспект K07 · Модуль M1. Python intensive: файлы, JSON, CSV, YAML · Редакция 2.1 · языковая вычитка · полный код практик в аккордеоне · После CHECKPOINT-K06
До этого момента учебные программы в основном выводили результат на экран и не сохраняли его между запусками. В работе программиста беспилотных авиационных систем такое поведение почти неприемлемо. Телеметрию необходимо сохранять. Параметры соединения необходимо читать с диска. Траекторию полёта часто требуется представить в виде таблицы. На этом уроке вы научитесь записывать и читать текстовые файлы, освоите три распространённых формата данных — JSON, CSV и YAML — и разберёте аккуратный способ записи файла через промежуточный временный файл.
Ниже описано, как в этой редакции урока устроены примеры. В теоретических разделах каждый важный фрагмент кода приводится дважды. Сначала вы видите блок «код целиком»: в его начале указана только краткая цель, а далее следует сам код без подробных пояснений. Затем в раскрывающемся блоке аккордеона размещён тот же фрагмент с построчным разбором: после каждой смысловой строки добавлен комментарий преподавателя с префиксом «# →». В разделе практики для каждой задачи в аккордеоне вложен полный текст учебного файла. Этот текст совпадает с файлом в каталоге code/M01_python/. Если урок уже открыт на сайте, вы можете скопировать код прямо отсюда в проект PyCharm.
Главная мысль урока состоит в следующем. Файл на диске позволяет сохранить структуру данных между отдельными запусками программы. Формат JSON удобен в тех случаях, когда нужно сохранить вложенные объекты языка Python в виде, близком к их внутренней структуре. Формат CSV удобен, когда требуется таблица для электронных таблиц или для простого построения графика. Формат YAML удобен, когда файл конфигурации должен читать и изменять человек. Кодировку UTF-8 при работе с текстом следует указывать явно. Файлы, от которых зависит дальнейший запуск, предпочтительно сначала записывать под временным именем, а затем замещать ими целевой файл.
Содержание
- 1. Цели урока
- 2. Словарь урока
- 3. Зачем файлы программисту БПЛА
- 4. Пути и pathlib
- 5. Текстовые файлы и UTF-8
- 6. Формат JSON
- 7. Формат CSV
- 8. Формат YAML
- 9. Аккуратная запись через временный файл
- 10. Какой формат выбрать
- 11. Типичные ошибки
- 12. Практика (полный код в аккордеоне)
- 13. Проверьте себя
- 14. Чек-лист самопроверки
- 15. Что дальше
1. Цели урока
После изучения этого урока вы будете уметь выполнять следующие действия.
- Вы будете строить пути к файлам через pathlib.Path и проверять, существует ли файл.
- Вы будете записывать и читать текстовые файлы в кодировке UTF-8.
- Вы будете сохранять словарь Python в JSON и загружать его обратно.
- Вы будете записывать последовательность отсчётов телеметрии в CSV и читать строки таблицы с преобразованием чисел.
- Вы будете понимать назначение YAML для конфигураций и запускать учебный сценарий с YAML или с запасным JSON.
- Вы будете выполнять аккуратную запись файла через временное имя и замену.
- Вы будете выбирать формат под задачу: конфиг, обмен объектами, представлять траекторию полёта в виде таблицы.
2. Словарь урока
| Термин | Простыми словами |
|---|---|
| Файл | Именованная область данных на диске, которую программа может создать, прочитать, изменить или удалить. |
| Путь | Адрес файла или папки в файловой системе. |
| pathlib | Стандартный модуль Python для работы с путями как с объектами. |
| Кодировка UTF-8 | Способ представления текста в байтах; для кириллицы на курсе указываем её явно. |
| JSON | Текстовый формат обмена структурированными данными; хорошо ложится на dict и list. |
| CSV | Текстовая таблица: строки записей и столбцы полей, обычно через запятую. |
| YAML | Текстовый формат конфигураций, удобный для чтения человеком. |
| Сериализация | Превращение объектов программы в текст или байты для хранения и передачи. |
| Атомарная запись | Приём: сначала писать во временный файл, затем заменить им целевой файл, чтобы не оставить «обрезанный» результат. |
3. Зачем файлы программисту БПЛА
Программа наземной станции управления и программа бортового компьютера-компаньона обычно используются дольше одного запуска. После перезапуска им снова требуются адрес подключения, пороги безопасности и нередко последний маршрут. Кроме того, инженеру необходимо уметь сохранять результаты работы: таблицу высот, снимок параметров и отчёт о проверке.
Поэтому работа с файлами в курсе не является посторонней «офисной» темой. Она входит в тот же круг навыков, что и обмен сообщениями MAVLink. Сначала вы осваиваете запись и чтение на учебных данных. Затем вы перенесёте те же приёмы на журналы и файлы конфигурации симулятора и бортового комплекса.
| Задача | Типичный формат |
|---|---|
| Сохранить один снимок телеметрии или набор параметров | JSON |
| Сохранить траекторию полёта: время, высота и режим — по строкам таблицы | CSV |
| Хранить конфиг соединения и порогов для человека | YAML (иногда JSON) |
| Короткий человеческий отчёт | Обычный .txt |
4. Пути и pathlib
pathlib — это стандартный модуль Python, который представляет путь к файлу или папке объектом класса Path. Объект Path удобнее обычной текстовой строки: к нему можно безопасно добавлять части пути, проверять существование файла и читать текст.
Код целиком.
# Пример: путь к файлу рядом со скриптом
from pathlib import Path
here = Path(__file__).resolve().parent
out_dir = here / "k07_data"
out_dir.mkdir(exist_ok=True)
note_path = out_dir / "hello_note.txt"
print(note_path)
print("exists before write:", note_path.exists())
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с последовательности символов «# →», содержат комментарий преподавателя. Эти строки не являются обязательной частью программы, которую вы будете сдавать как готовый производственный код.
from pathlib import Path # → Подключаем стандартный модуль для работы с путями как с объектами. here = Path(__file__).resolve().parent # → Path(__file__) — путь к текущему .py-файлу. resolve() делает путь полным. parent — каталог, где лежит файл. out_dir = here / "k07_data" # → Оператор «/» у Path добавляет часть пути. Получается папка k07_data рядом со скриптом. out_dir.mkdir(exist_ok=True) # → Создаём папку. Если она уже есть, ошибки не будет. note_path = out_dir / "hello_note.txt" # → Собираем полный путь к файлу hello_note.txt внутри этой папки. print(note_path) # → Печатаем путь, чтобы увидеть, куда программа будет писать. print("exists before write:", note_path.exists()) # → exists() отвечает True/False: есть ли уже такой файл на диске.
5. Текстовые файлы и UTF-8
Кодировка UTF-8 — это согласованный способ представлять символы текста, включая кириллицу, в виде байтов на диске. На курсе при работе с текстом мы указываем encoding="utf-8" явно. Тогда поведение программы на системе Windows становится предсказуемым.
Код целиком.
# Пример: запись и чтение текста в UTF-8
from pathlib import Path
path = Path("k07_data") / "hello_note.txt"
path.parent.mkdir(exist_ok=True)
path.write_text("Строка один\nСтрока два\n", encoding="utf-8")
text = path.read_text(encoding="utf-8")
print(text)
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с последовательности символов «# →», содержат комментарий преподавателя. Эти строки не являются обязательной частью программы, которую вы будете сдавать как готовый производственный код.
from pathlib import Path # → Снова импортируем Path, чтобы указать путь к текстовому файлу. path = Path("k07_data") / "hello_note.txt" # → Путь относительно текущей рабочей папки запуска (в практике task1 путь привязан к __file__). path.parent.mkdir(exist_ok=True) # → parent — каталог файла; создаём его при необходимости. path.write_text("Строка один\nСтрока два\n", encoding="utf-8") # → write_text записывает весь текст целиком. encoding="utf-8" сохраняет кириллицу предсказуемо. text = path.read_text(encoding="utf-8") # → read_text читает весь файл в одну строку Python. print(text) # → Печатаем прочитанное, чтобы убедиться, что запись удалась.
Контекстный менеджер with гарантирует закрытие файла даже при ошибке внутри блока. Для CSV он особенно привычен.
Код целиком.
# Пример: with гарантирует закрытие файла
from pathlib import Path
path = Path("k07_data") / "lines.txt"
with path.open("w", encoding="utf-8") as f:
f.write("first\n")
f.write("second\n")
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с последовательности символов «# →», содержат комментарий преподавателя. Эти строки не являются обязательной частью программы, которую вы будете сдавать как готовый производственный код.
from pathlib import Path # → Импортируем класс Path из модуля pathlib. path = Path("k07_data") / "lines.txt" # → Задаём путь к файлу, который будет создан. with path.open("w", encoding="utf-8") as f: # → open открывает файл на запись («w»). with закроет файл даже при ошибке внутри блока. f.write("first\n") # → Пишем первую строку. \n — перевод строки. f.write("second\n") # → Пишем вторую строку. # здесь файл уже закрыт # → После выхода из with дескриптор файла закрыт автоматически.
6. Формат JSON
JSON (JavaScript Object Notation) — текстовый формат хранения и обмена структурированными данными. Для Python он особенно удобен: словарь dict и список list переводятся в JSON почти напрямую.
Сериализация — это превращение объектов программы в текст или байты, чтобы их можно было сохранить или передать. Обратный процесс называют десериализацией: текст снова становится объектами Python.
Код целиком.
# Пример: dict → JSON → dict
import json
from pathlib import Path
sample = {
"mode": "GUIDED",
"altitude_m": 12.5,
"link_ok": True,
}
path = Path("k07_data") / "telemetry_sample.json"
text = json.dumps(sample, ensure_ascii=False, indent=2)
path.write_text(text, encoding="utf-8")
loaded = json.loads(path.read_text(encoding="utf-8"))
print(loaded["mode"], loaded["altitude_m"])
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с последовательности символов «# →», содержат комментарий преподавателя. Эти строки не являются обязательной частью программы, которую вы будете сдавать как готовый производственный код.
import json # → Стандартный модуль для JSON. from pathlib import Path # → Импортируем pathlib для указания пути к файлу. sample = { # → Обычный словарь Python — учебный снимок телеметрии. "mode": "GUIDED", # → Ключ mode — строка с режимом. "altitude_m": 12.5, # → Высота числом float. "link_ok": True, # → Логический флаг. } # → Конец словаря. path = Path("k07_data") / "telemetry_sample.json" # → Куда сохраним JSON-файл. text = json.dumps(sample, ensure_ascii=False, indent=2) # → dumps: объект Python → текст JSON. ensure_ascii=False оставляет кириллицу читаемой. indent=2 делает отступы. path.write_text(text, encoding="utf-8") # → Записываем JSON-текст на диск. loaded = json.loads(path.read_text(encoding="utf-8")) # → loads: текст JSON → снова dict/list в Python. print(loaded["mode"], loaded["altitude_m"]) # → Проверяем, что поля на месте после круглого пути запись→чтение.
| Параметр dumps | Зачем |
|---|---|
| ensure_ascii=False | Кириллические символы остаются читаемыми в файле |
| indent=2 | Удобные для чтения отступы; файл проще просматривать человеку |
k07_task2_json_telemetry.py вложен в аккордеон задачи 7.2 ниже.7. Формат CSV
CSV (Comma-Separated Values) — текстовый табличный формат. Каждая строка файла — запись. Поля внутри строки обычно разделены запятой. Такой файл легко открыть в Excel и так же легко дописать построчно из программы.
Для последовательности отсчётов телеметрии формат CSV естественен: одна строка соответствует одному моменту времени, а столбцы содержат поля t_s, alt_m, mode и другие величины.
Код целиком.
# Пример: list[dict] → CSV → чтение с float()
import csv
from pathlib import Path
path = Path("k07_data") / "track_demo.csv"
rows = [
{"t_s": 0.0, "alt_m": 0.5, "mode": "STABILIZE"},
{"t_s": 1.0, "alt_m": 5.0, "mode": "GUIDED"},
]
fieldnames = ["t_s", "alt_m", "mode"]
with path.open("w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for row in rows:
writer.writerow(row)
with path.open("r", encoding="utf-8", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
alt_m = float(row["alt_m"])
print(row["mode"], alt_m)
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с последовательности символов «# →», содержат комментарий преподавателя. Эти строки не являются обязательной частью программы, которую вы будете сдавать как готовый производственный код.
import csv # → Стандартный модуль таблиц CSV. from pathlib import Path # → Импортируем pathlib для построения путей к файлам. path = Path("k07_data") / "track_demo.csv" # → Задаём путь к CSV-файлу таблицы. rows = [ # → Список словарей — одна строка таблицы = один dict. {"t_s": 0.0, "alt_m": 0.5, "mode": "STABILIZE"}, # → Первая точка траектории. {"t_s": 1.0, "alt_m": 5.0, "mode": "GUIDED"}, # → Вторая точка траектории. ] # → Конец списка. fieldnames = ["t_s", "alt_m", "mode"] # → Порядок и имена столбцов. with path.open("w", encoding="utf-8", newline="") as f: # → Открываем на запись. newline="" — рекомендация для csv на Windows. writer = csv.DictWriter(f, fieldnames=fieldnames) # → Писатель, который понимает dict. writer.writeheader() # → Первая строка файла — заголовки столбцов. for row in rows: # → Для каждой записи… writer.writerow(row) # → …пишем строку таблицы. with path.open("r", encoding="utf-8", newline="") as f: # → Открываем тот же файл на чтение. reader = csv.DictReader(f) # → Читатель отдаёт каждую строку как dict. for row in reader: # → Обходим строки данных. alt_m = float(row["alt_m"]) # → Важно: из CSV числа приходят строками. float() делает число. print(row["mode"], alt_m) # → Печатаем режим и высоту.
k07_task3_csv_track.py — в задаче 7.3.8. Формат YAML
YAML — текстовый формат, который часто используют для конфигурационных файлов. Его удобно читать глазами: структура задаётся отступами, меньше служебных скобок, чем в JSON.
Типичный учебный файл конфигурации наземного сценария может хранить тип соединения, сетевой адрес, номер порта и пороги безопасности. Оператор открывает файл, изменяет порт симулятора SITL и запускает программу снова.
Пример внешнего вида файла конфигурации (это текст YAML, а не программа Python):
# Пример вида app_config.yaml (учебный текст, не Python)
connection:
type: udp
address: 127.0.0.1
port: 14550
safety:
min_voltage_v: 14.0
require_operator_ack: true
python -m pip install pyyaml внутри venv. На K07 практика устроена мягко: если PyYAML ещё не установлен, скрипт задачи 7.4 сохранит тот же смысл в JSON и подскажет команду установки на потом. Принудительно ставить пакет прямо сейчас не требуется.k07_task4_yaml_config.py — в задаче 7.4 (оба пути: YAML и JSON-запасной).9. Аккуратная запись через временный файл
Атомарная запись в учебном смысле — это приём, при котором программа сначала записывает данные во временный файл, а затем заменяет им целевой файл. Если запись оборвётся на середине, старый целевой файл с большей вероятностью останется целым, а «обрезанным» окажется только временный.
Код целиком.
# Пример: запись через временный файл и os.replace
from pathlib import Path
import json
import os
final_path = Path("k07_data") / "settings.json"
tmp_path = Path("k07_data") / "settings.json.tmp"
final_path.parent.mkdir(exist_ok=True)
payload = json.dumps({"version": 1, "ok": True}, ensure_ascii=False, indent=2)
tmp_path.write_text(payload, encoding="utf-8")
os.replace(tmp_path, final_path)
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с последовательности символов «# →», содержат комментарий преподавателя. Эти строки не являются обязательной частью программы, которую вы будете сдавать как готовый производственный код.
from pathlib import Path # → Импортируем pathlib для построения путей к файлам. import json # → Импортируем json, чтобы сформировать учебный JSON-текст. import os # → Импортируем os: функция os.replace заместит целевой файл временным. final_path = Path("k07_data") / "settings.json" # → Итоговое имя, которое должна видеть программа. tmp_path = Path("k07_data") / "settings.json.tmp" # → Временное имя на время записи. final_path.parent.mkdir(exist_ok=True) # → Каталог должен существовать. payload = json.dumps({"version": 1, "ok": True}, ensure_ascii=False, indent=2) # → Готовим полное содержимое в памяти. tmp_path.write_text(payload, encoding="utf-8") # → Шаг 1: полностью записываем временный файл. os.replace(tmp_path, final_path) # → Шаг 2: заменяем целевой файл готовым временным. Так меньше шанс «обрезанного» конфига.
k07_task5_atomic_write.py — в задаче 7.5.10. Какой формат выбрать
| Вопрос | Если ответ утвердительный, предпочтителен формат |
|---|---|
| Требуется сохранить вложенный объект, например словарь внутри словаря, а затем снова получить его в программе на Python? | JSON |
| Требуется таблица по времени для работы в табличном редакторе или для простого анализа столбцов? | CSV |
| Файл конфигурации должен изменять человек в текстовом редакторе, и важна удобочитаемость? | YAML (или аккуратный JSON) |
| Требуется короткий текстовый журнал для просмотра человеком без строгой структуры? | Обычный текстовый файл |
11. Типичные ошибки
| Ошибка | Что происходит | Как думать |
|---|---|---|
| Забыли encoding="utf-8" | Нарушается отображение кириллицы | Для текстовых файлов курса всегда указывайте кодировку UTF-8 |
| Читаете CSV и складываете строки как числа | Получается неверный результат либо возникает ошибка типа | Сначала преобразуйте значение через float(...) или int(...) |
| Пишете JSON вручную «как текст» с ошибкой запятой | Вызов json.loads завершается ошибкой | Соберите объект Python и выполните сериализацию через dumps |
| Открыли файл и забыли закрыть в длинной программе | Возможны утечки дескрипторов и блокировки файла | Открывайте файл с помощью оператора with |
| Пишете конфиг поверх себя и обрыв процесса | На диске остаётся неполностью записанный файл | Сначала запишите временный файл, затем выполните os.replace |
| Кладёте секреты в Git | Возможна утечка конфиденциальных данных | Исключайте секреты через .gitignore и храните их вне репозитория |
12. Практика (полный код в аккордеоне)
В каждой карточке задачи ниже в раскрывающемся блоке приведён полный текст соответствующего учебного файла. Этот текст совпадает с файлами в каталоге code/M01_python/. Рекомендуется такой порядок работы. Сначала внимательно прочитайте условие. Затем раскройте аккордеон, скопируйте код в файл проекта под тем же именем, запустите его в виртуальном окружении и сверьте вывод с ожидаемым результатом. Каталог k07_data/ учебные сценарии создадут самостоятельно.
Задача 7.1. Path, запись и чтение текста
Файл практики: k07_task1_path_write_read.py.
Создайте текстовый файл через pathlib, запишите две строки, прочитайте файл обратно, напечатайте признак существования и размер в байтах.
Ожидаемый результат. В консоли путь к hello_note.txt, текст из двух строк, exists: True и ненулевой size_bytes.
- Полный текст файла k07_task1_path_write_read.py
Скопируйте приведённое ниже содержимое в файл
code/M01_python/k07_task1_path_write_read.pyв проекте PyCharm (venv) и запустите. Ниже приведён полный учебный текст файла с комментариями.# k07_task1_path_write_read.py # Цель: pathlib.Path — путь к файлу; запись и чтение текста в UTF-8. # Запуск: из venv проекта. Файл появится рядом, в k07_data/. from pathlib import Path # Папка рядом с этим скриптом HERE = Path(__file__).resolve().parent OUT_DIR = HERE / "k07_data" OUT_DIR.mkdir(exist_ok=True) # Path — объект пути, а не просто строка note_path = OUT_DIR / "hello_note.txt" # Пишем текст. encoding="utf-8" — чтобы кириллица не ломалась. text = "UAV Python Pro\nK07: первая запись в файл\n" note_path.write_text(text, encoding="utf-8") print("written:", note_path) # Читаем обратно loaded = note_path.read_text(encoding="utf-8") print("loaded:") print(loaded) print("exists:", note_path.exists()) print("size_bytes:", note_path.stat().st_size)
Задача 7.2. JSON телеметрии
Файл практики: k07_task2_json_telemetry.py.
Сохраните учебный словарь телеметрии в JSON с ensure_ascii=False и indent=2, затем загрузите файл и напечатайте mode и altitude_m.
Ожидаемый результат. Файл telemetry_sample.json в k07_data; в консоли mode GUIDED и высота 12.5.
- Полный текст файла k07_task2_json_telemetry.py
Скопируйте приведённое ниже содержимое в файл
code/M01_python/k07_task2_json_telemetry.pyв проекте PyCharm (venv) и запустите. Ниже приведён полный учебный текст файла с комментариями.# k07_task2_json_telemetry.py # Цель: сохранить dict/list в JSON и прочитать обратно. # JSON удобен для обмена структурированными данными между программами. import json from pathlib import Path HERE = Path(__file__).resolve().parent OUT = HERE / "k07_data" OUT.mkdir(exist_ok=True) path = OUT / "telemetry_sample.json" # Учебный снимок телеметрии (не MAVLink-кадр) sample = { "vehicle": "sitl-copter-demo", "mode": "GUIDED", "altitude_m": 12.5, "battery_v": 15.8, "satellites": 14, "link_ok": True, } # ensure_ascii=False — кириллица в файле читается как текст, не \uXXXX # indent=2 — красивые отступы для человека path.write_text( json.dumps(sample, ensure_ascii=False, indent=2), encoding="utf-8", ) print("json written:", path) # loads/load: из текста/файла обратно в объекты Python raw = path.read_text(encoding="utf-8") loaded = json.loads(raw) print("mode from file:", loaded["mode"]) print("altitude_m from file:", loaded["altitude_m"])
Задача 7.3. CSV-файл траектории
Файл практики: k07_task3_csv_track.py.
Запишите три строки траектории через csv.DictWriter и прочитайте их DictReader с преобразованием t_s и alt_m через float.
Ожидаемый результат. Файл track_demo.csv; три строки печати t=… alt=… mode=…
- Полный текст файла k07_task3_csv_track.py
Скопируйте приведённое ниже содержимое в файл
code/M01_python/k07_task3_csv_track.pyв проекте PyCharm (venv) и запустите. Ниже приведён полный учебный текст файла с комментариями.# k07_task3_csv_track.py # Цель: записать последовательность отсчётов телеметрии в CSV и прочитать строки обратно. # CSV удобен для Excel и простых графиков. import csv from pathlib import Path HERE = Path(__file__).resolve().parent OUT = HERE / "k07_data" OUT.mkdir(exist_ok=True) path = OUT / "track_demo.csv" # list[dict] — формат, который вы уже знаете с K04/K05 rows = [ {"t_s": 0.0, "alt_m": 0.5, "mode": "STABILIZE"}, {"t_s": 1.0, "alt_m": 5.0, "mode": "GUIDED"}, {"t_s": 2.0, "alt_m": 12.0, "mode": "AUTO"}, ] fieldnames = ["t_s", "alt_m", "mode"] # newline="" — рекомендация документации csv на Windows with path.open("w", encoding="utf-8", newline="") as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() for row in rows: writer.writerow(row) print("csv written:", path) # Чтение with path.open("r", encoding="utf-8", newline="") as f: reader = csv.DictReader(f) for row in reader: # значения из CSV приходят строками — для чисел нужен float() t_s = float(row["t_s"]) alt_m = float(row["alt_m"]) mode = row["mode"] print(f"t={t_s} alt={alt_m} mode={mode}")
Задача 7.4. YAML-конфиг или JSON-запасной путь
Файл практики: k07_task4_yaml_config.py.
Запустите скрипт. Если установлен PyYAML, будет записан app_config.yaml. Если нет — app_config_fallback.json и подсказка про pip install pyyaml. В обоих случаях напечатайте порт 14550 из загруженной структуры.
Ожидаемый результат. В консоли udp port: 14550 и сообщение о YAML либо о JSON fallback.
- Полный текст файла k07_task4_yaml_config.py
Скопируйте приведённое ниже содержимое в файл
code/M01_python/k07_task4_yaml_config.pyв проекте PyCharm (venv) и запустите. Ниже приведён полный учебный текст файла с комментариями.# k07_task4_yaml_config.py # Цель: понять YAML как человекочитаемый конфиг. # PyYAML может быть не установлен — поэтому есть два режима: # 1) если import yaml работает — пишем и читаем .yaml # 2) иначе — сохраняем тот же смысл в .json и объясняем, что поставить позже from pathlib import Path import json HERE = Path(__file__).resolve().parent OUT = HERE / "k07_data" OUT.mkdir(exist_ok=True) config = { "connection": { "type": "udp", "address": "127.0.0.1", "port": 14550, }, "safety": { "min_voltage_v": 14.0, "require_operator_ack": True, }, "mission": { "default_alt_m": 40.0, }, } try: import yaml # type: ignore except ImportError: yaml = None if yaml is not None: path = OUT / "app_config.yaml" # allow_unicode=True — кириллица, если появится в конфиге text = yaml.safe_dump(config, allow_unicode=True, sort_keys=False) path.write_text(text, encoding="utf-8") loaded = yaml.safe_load(path.read_text(encoding="utf-8")) print("yaml written:", path) print("udp port:", loaded["connection"]["port"]) else: # Запасной путь без дополнительной установки пакета path = OUT / "app_config_fallback.json" path.write_text(json.dumps(config, ensure_ascii=False, indent=2), encoding="utf-8") print("PyYAML not installed — wrote JSON fallback:", path) print("Later (when mentor says): python -m pip install pyyaml") loaded = json.loads(path.read_text(encoding="utf-8")) print("udp port:", loaded["connection"]["port"])
Задача 7.5. Запись через временный файл
Файл практики: k07_task5_atomic_write.py.
Запишите JSON во временный файл settings.json.tmp, затем os.replace в settings.json, прочитайте итоговый файл.
Ожидаемый результат. Файл settings.json; в консоли final: … и JSON с version и ok.
- Полный текст файла k07_task5_atomic_write.py
Скопируйте приведённое ниже содержимое в файл
code/M01_python/k07_task5_atomic_write.pyв проекте PyCharm (venv) и запустите. Ниже приведён полный учебный текст файла с комментариями.# k07_task5_atomic_write.py # Цель: «атомарная» запись — сначала временный файл, потом replace. # Так меньше шанс получить полузаписанный конфиг при сбое. from pathlib import Path import json import os HERE = Path(__file__).resolve().parent OUT = HERE / "k07_data" OUT.mkdir(exist_ok=True) final_path = OUT / "settings.json" tmp_path = OUT / "settings.json.tmp" data = {"version": 1, "vehicle": "demo", "ok": True} payload = json.dumps(data, ensure_ascii=False, indent=2) # 1) пишем во временный файл tmp_path.write_text(payload, encoding="utf-8") # 2) атомарно (насколько позволяет ОС) заменяем целевой файл os.replace(tmp_path, final_path) print("final:", final_path) print("content:", final_path.read_text(encoding="utf-8"))
Задача 7.6. Git commit
Сохраните результаты практики в истории Git. Каталог k07_data/ с выходными учебными файлами в репозиторий обычно не включают. При необходимости добавьте строку k07_data/ в файл .gitignore.
git add code/M01_python/k07_*.py
git commit -m "K07: pathlib json csv yaml atomic write practice"
13. Проверьте себя
- Чем объект Path удобнее строки с путём?
- Почему на курсе для текста мы указываем encoding="utf-8"?
- Чем JSON удобен для dict и list?
- Почему после csv.DictReader числовые поля нужно преобразовывать через float или int?
- Для какой задачи YAML обычно предпочтительнее «плотного» JSON?
- Что делает os.replace после записи временного файла и зачем так делают?
- Какой формат выберете для траектории высоты по времени и почему?
- Почему секреты не следует класть в учебный репозиторий?
- Зачем в уроке два представления одного и того же кода: «целиком» и «построчный разбор»?
14. Чек-лист самопроверки
- Строю пути через pathlib.Path и создаю папку exist_ok=True
- Пишу и читаю текст в UTF-8
- Сохраняю и загружаю JSON
- Пишу и читаю CSV, преобразую числа при чтении
- Понимаю роль YAML для конфигов и запасной путь без PyYAML
- Выполняю запись через временный файл и replace
- Могу выбрать JSON / CSV / YAML под задачу
- Открыл аккордеоны практики и сверил полный код с запуском в виртуальном окружении
- Запускал k07_task1 … k07_task5 в venv
- Сделал git commit по K07
15. Что дальше
- Предыдущий урок: K06 · Модули, пакеты, venv, pip
- Текущий урок: K07 · Файлы, JSON, CSV, YAML (редакция 2.0, новый шаблон кода)
- Следующий урок: K08 · Исключения, logging, отладка (будет переведён на тот же шаблон)
- Горизонт модуля M1: K12 и гейт G1
docs/06_ZOO_PUBLISH_SPEC.md.