k04. Коллекции list, tuple, dict, set
UAV Python Pro · Конспект K04 · Модуль M1. Python intensive: коллекции list, tuple, dict, set · Редакция 1.2 · правка ученика + QA · После CHECKPOINT-K03
На прошлом уроке вы научились хранить отдельные значения параметров телеметрии: одну высоту, один режим, один флаг связи. В реальной работе с БПЛА значения почти всегда поступают группами: список точек маршрута, словарь параметров автопилота, набор уникальных режимов из лога, очередь последних отсчётов телеметрии. На этом уроке вы разберёте четыре встроенные коллекции Python — list, tuple, dict и set — и поймёте, какую из них выбирать под задачу БПЛА. Практика выполняется в виртуальном окружении проекта из K01. Готовые файлы находятся в папке code/M01_python/.
Главная мысль урока: коллекция — это способ держать много связанных значений под одним именем и обходить их циклом. Список (list) удобен, когда важен порядок и нужны изменения. Кортеж (tuple) — когда набор координат «зафиксирован» и его не должны случайно изменить. Словарь (dict) — когда доступ идёт по имени, как к параметру RTL_ALT. Множество (set) — когда важны уникальные элементы, например какие режимы вообще встречались в логе.
Содержание
1. Цели урока
После этого урока вы будете уметь своими словами и в коде:
- создавать списки, читать элементы по индексу, брать срезы, добавлять элементы;
- объяснить, чем кортеж отличается от списка, и когда кортеж уместен для точки маршрута;
- создавать словарь параметров, читать значение по ключу, безопасно использовать метод get, обновлять значение;
- собирать множество уникальных режимов из «лога» и проверять вхождение элемента;
- выбрать подходящую коллекцию под задачу (маршрут, параметры, уникальные режимы, пачка телеметрии);
- написать простой list comprehension для фильтрации учебной телеметрии;
2. Словарь урока
| Термин | Простыми словами |
|---|---|
| Коллекция | Объект, который хранит несколько значений и умеет их отдавать по одному (часто в цикле). |
| list (список) | Упорядоченная изменяемая последовательность. Квадратные скобки: [1, 2, 3]. |
| tuple (кортеж) | Упорядоченная, но неизменяемая последовательность. Круглые скобки: (lat, lon, alt). |
| dict (словарь) | Набор пар «ключ → значение». Фигурные скобки: {"RTL_ALT": 5000}. |
| set (множество) | Набор уникальных элементов; на порядок элементов при печати для маршрута опираться нельзя. Фигурные скобки: {"AUTO", "RTL"}. |
| Индекс | Номер позиции в списке или кортеже. В Python нумерация с нуля: первый элемент имеет индекс 0. |
| Срез (slice) | Кусок последовательности: modes[2:4] — элементы с индекса 2 включительно по 4 не включая. |
| Ключ (key) | Имя, по которому словарь находит значение. Часто строка: "BATT_LOW_VOLT". |
| Итерировать | Обходить элементы по одному, обычно циклом for. |
| list comprehension | Короткая запись создания нового списка из старого с фильтром или преобразованием. |
| Mutable / immutable | Изменяемый / неизменяемый объект. Список меняют на месте; кортеж после создания не изменяют. |
3. Зачем коллекции программисту БПЛА
Представьте, что вы пишете маленький наземный помощник. За одну минуту он может получить десятки сообщений телеметрии, список точек миссии и таблицу параметров. Если завести отдельную переменную на каждое число, код станет трудночитаемым из-за множества имён. Коллекции дают структуру.
| Задача | Удобная коллекция | Почему |
|---|---|---|
| Порядок режимов полёта, которые вы перебираете в меню | list | Важен порядок, список можно дополнять |
| Одна точка: широта, долгота, высота | tuple | Фиксированный набор полей, случайно «не дописать» четвёртое число сложнее |
| Параметры автопилота по имени | dict | Набор пар «имя → значение»: обращаетесь по имени, а не по номеру. Пример: params["RTL_ALT"] сразу даёт нужное значение. |
| Какие режимы встретились в логе хотя бы раз | set | Дубликаты исчезают сами |
| Пачка отсчётов телеметрии | list of dict | Список словарей — очень частый учебный и практический формат |
RTL_ALT — высота, связанная с возвратом домой (конкретные единицы и смысл зависят от прошивки; сейчас нам важно только имя). Если хранить настройки простым списком чисел, пришлось бы помнить: «высота RTL — это третий элемент списка». Завтра список перестроят, и третий элемент станет уже другой настройкой. Словарь решает это иначе: вы пишете обращение к словарю params и в квадратных скобках указываете имя RTL_ALT. Python сам находит нужное значение по этому имени. Номер позиции в памяти вам помнить не нужно.4. Список list
Создание, индексы, срезы
Список создают квадратными скобками. Элементы разделяют запятыми. Порядок сохраняется.
modes = ["STABILIZE", "LOITER", "GUIDED", "AUTO", "RTL"]
print(modes)
print(len(modes)) # сколько элементов
print(modes[0]) # первый — STABILIZE
print(modes[-1]) # последний — RTL
print(modes[2:4]) # с индекса 2 до 4 не включая → GUIDED, AUTO
Добавление и изменение
modes = ["LOITER", "GUIDED"]
modes.append("AUTO") # добавить в конец
modes[0] = "STABILIZE" # заменить элемент
print(modes)
Полезные методы на старте:
| Действие | Пример | Смысл |
|---|---|---|
| Добавить в конец | modes.append("RTL") | Самый частый способ пополнить список |
| Вставить по позиции | modes.insert(1, "LOITER") | Сдвиг остальных вправо |
| Удалить значение | modes.remove("AUTO") | Удаляет первое совпадение |
| Удалить по индексу | last = modes.pop() | pop() без аргумента удаляет последний элемент |
| Найти индекс | modes.index("GUIDED") | ValueError, если нет такого элемента |
| Посчитать вхождения | modes.count("LOITER") | Сколько раз значение встречается |
Обход списка и enumerate
Обход значит: взять элементы по одному и с каждым что-то сделать. В Python для этого обычно пишут цикл for.
# Список учебных имён режимов полёта (порядок важен)
modes = ["GUIDED", "AUTO", "RTL"]
# Простой обход: на каждом шаге mode — очередная строка из списка
for mode in modes:
print("mode:", mode)
# enumerate — встроенная функция Python.
# Она к каждому элементу «приклеивает» номер позиции (с нуля).
# i — номер (0, 1, 2, ...)
# mode — сам элемент списка
for i, mode in enumerate(modes):
print(f"[{i}] {mode}")
5. Кортеж tuple
Кортеж похож на список: есть порядок и индексы. Главное отличие — после создания кортеж не предназначен для изменения на месте. Нельзя сделать wp[0] = ... и нельзя append.
# (широта, долгота, высота_м)
wp = (55.751244, 37.618423, 40.0)
lat, lon, alt_m = wp # распаковка
print(lat, lon, alt_m)
print(wp[2]) # высота
Список кортежей — удобная учебная миссия:
mission = [
(55.751244, 37.618423, 0.0),
(55.752000, 37.620000, 40.0),
(55.753500, 37.615000, 40.0),
]
for i, wp in enumerate(mission):
lat, lon, alt_m = wp
print(f"WP{i}: {lat:.6f}, {lon:.6f}, {alt_m:.1f} m")
6. Словарь dict
Ключ и значение
Словарь хранит пары. Слева ключ, справа значение. Для параметров автопилота это самый естественный вид.
params = {
"FRAME_CLASS": 1,
"RTL_ALT": 5000,
"FS_GCS_ENABLE": 1,
"BATT_LOW_VOLT": 14.4,
}
print(params["RTL_ALT"])
params["BATT_LOW_VOLT"] = 14.2
print(params["BATT_LOW_VOLT"])
Безопасное чтение get
params = {"RTL_ALT": 5000}
print(params.get("RTL_ALT")) # 5000
print(params.get("Q_ENABLE")) # None, если ключа нет
print(params.get("Q_ENABLE", "not set")) # значение по умолчанию
Обход словаря: метод items
Часто нужно не одно значение, а все пары из словаря по очереди. Например, напечатать учебный набор параметров на экран или записать их в файл лога. Это похоже на то, как вы открываете тетрадь и читаете строку за строкой: слева название настройки, справа её число.
Простыми словами, что такое items. У словаря есть метод (то есть встроенная команда объекта) с именем items. Когда вы пишете params.items(), Python не возвращает «просто список чисел». Он даёт последовательность пар. Каждая пара состоит из двух частей:
- слева — ключ (имя параметра, строка вроде RTL_ALT);
- справа — значение (число или другой объект, который хранится под этим именем).
Цикл for забирает эти пары по одной. Запись for name, value in ... называется распаковкой: первая часть пары попадает в переменную name, вторая — в переменную value. Имена переменных вы выбираете сами; name и value — просто понятные слова «имя» и «значение».
# Учебный словарь: имя параметра → значение
# (в PyCharm пишите обычные символы; на сайте для ZOO знаки сравнения могут быть полноширинными)
params = {
"RTL_ALT": 5000, # учебная высота RTL (смысл единиц — позже)
"FS_GCS_ENABLE": 1, # 1 часто значит «включено» в учебных примерах
}
# params.items() отдаёт пары (ключ, значение) по одной
for name, value in params.items():
# name — строка с именем параметра
# value — то, что лежит в словаре под этим именем
print(f"{name} = {value}")
# Только ключи (имена), без значений:
print("имена:", list(params.keys()))
# Только значения, без имён:
print("значения:", list(params.values()))
for x in params:, Python по умолчанию перебирает только ключи (только имена). Значения сами не придут. Метод items как раз говорит: «дай и имя, и значение вместе». Есть ещё keys() — только имена, и values() — только значения. Для печати «параметр = число» почти всегда нужен именно items.Проверка «есть ли такой ключ в словаре» — отдельная операция, не путайте её с items:
params = {"RTL_ALT": 5000}
# Оператор in для словаря проверяет КЛЮЧИ (имена), не значения
if "RTL_ALT" in params:
print("Параметр RTL_ALT в словаре есть")
else:
print("Параметра RTL_ALT нет")
↑ К оглавлению7. Множество set
Множество хранит каждый элемент только один раз. Порядок при печати не стоит воспринимать как «закон маршрута» — для упорядоченных последовательностей берите list.
log_modes = ["LOITER", "LOITER", "GUIDED", "AUTO", "AUTO", "RTL"]
unique = set(log_modes)
print(unique)
print("AUTO" in unique) # True
print("ACRO" in unique) # False
unique.add("LAND")
unique.discard("ACRO") # удалить, если есть; если нет - ошибки не будет
print(sorted(unique)) # sorted даёт обычный список по алфавиту
8. Что выбирать под задачу
| Вопрос себе | Если да |
|---|---|
| Важен порядок и состав будет меняться? | list |
| Фиксированная структура из нескольких полей (точка, RGB, xyz)? | tuple (позже dataclass) |
| Ищу значение по имени/строковому коду? | dict |
| Нужны только уникальные элементы и проверка «уже видел»? | set |
| Пачка однотипных записей с полями? | list, а внутри dict или tuple |
9. List comprehension (кратко)
Когда нужно построить новый список из старого, Python позволяет записать это компактно. Всегда умейте сделать то же самым циклом for. Comprehension не обязателен, но часто очень удобен.
samples = [
{"alt_m": 5.0, "mode": "GUIDED"},
{"alt_m": 12.0, "mode": "AUTO"},
{"alt_m": 20.0, "mode": "AUTO"},
]
alts = [s["alt_m"] for s in samples]
print(alts)
auto_only = [s for s in samples if s["mode"] == "AUTO"]
print(len(auto_only))
Тот же смысл развёрнуто:
alts = []
for s in samples:
alts.append(s["alt_m"])
10. Типичные ошибки
| Ошибка | Что происходит | Как думать |
|---|---|---|
| Обращение к modes[10], а элементов пять | IndexError | Проверьте len и индексы с нуля |
| params["NOPE"] без проверки | KeyError | get("NOPE", default) или проверка in |
| wp.append(...) где wp — tuple | AttributeError | Кортеж не список; меняйте mission-список, не саму точку-tuple |
| Путаете {} для set и dict | {} — это пустой dict, не set | Пустое множество: set() |
| Копирование списка через b = a и правка b | Меняется и a | Пока запомните: b = list(a) или a.copy(); глубокое копирование — позже |
| Ждёте от set стабильный «порядок миссии» | Логика маршрута нарушается | Маршрут — list |
a = [1, 2, 3]
b = a # b — ещё одно имя того же списка
b.append(4)
print(a) # [1, 2, 3, 4] — сюрприз для новичка
a = [1, 2, 3]
b = list(a) # поверхностная копия списка
b.append(4)
print(a) # [1, 2, 3]
print(b) # [1, 2, 3, 4]
↑ К оглавлению11. Практика
Запускайте файлы из code/M01_python/ в venv проекта. Ниже — краткое содержание; полные скрипты уже в материалах курса.
Задача 4.1. Список режимов
Файл k04_task1_modes_list.py. Создайте список режимов, напечатайте первый и последний, срез, append, count, index.
Задача 4.2. Миссия из кортежей
Файл k04_task2_waypoint_tuples.py. Список из трёх точек (lat, lon, alt_m), обход с enumerate и распаковкой.
Задача 4.3. Словарь параметров
Файл k04_task3_params_dict.py. Учебный словарь PARAM, чтение, get для отсутствующего ключа, обновление, обход items. Не записывайте эти числа на реальный борт без понимания единиц и методики.
Задача 4.4. Уникальные режимы
Файл k04_task4_unique_modes_set.py. Из «лога» с повторами соберите set и ответьте, встречались ли AUTO и ACRO.
Задача 4.5. Пачка телеметрии
Файл k04_task5_telemetry_batch.py. Список словарей: высоты, минимум напряжения, только AUTO, предупреждение если высота выше учебного потолка 30 м. В файле сравнения — обычный Python; на сайте в общих правилах ZOO помните про полноширинные знаки в HTML-примерах.
Задача 4.6. Git commit
git add code/M01_python/k04_*.py
git commit -m "K04: list tuple dict set practice"
12. Проверьте себя
- Чем list отличается от tuple? Приведите пример точки маршрута.
- Почему параметры автопилота удобно хранить в dict, а не в list?
- Что вернёт params.get("NOPE", 0), если ключа нет?
- Зачем set при разборе лога режимов?
- Что такое индекс 0 и индекс -1 в списке?
- Чем опасна запись b = a для двух «списков», если потом менять b?
- Когда list comprehension уместен, а когда лучше обычный for?
- Какую коллекцию выберете для «очередь последних 50 высот» и почему?
13. Чек-лист самопроверки
- Создаю list, читаю [0] и [-1], делаю срез, append
- Обхожу список через for и enumerate
- Создаю tuple точки (lat, lon, alt) и распаковываю поля
- Понимаю, что tuple нельзя append
- Создаю dict параметров, читаю по ключу, обновляю значение
- Использую get со значением по умолчанию
- Обхожу dict через items
- Собираю set уникальных режимов и проверяю in
- Могу выбрать list/tuple/dict/set под задачу БПЛА
- Запускал k04_task1 … k04_task5 в venv
- Сделал git commit по K04
14. Что дальше
- Предыдущий: K03 · Синтаксис и типы
- Текущий: K04 · Коллекции
- Следующий: K05 · Функции и управление потоком
- Горизонт M1: K12 CLI-проект и гейт G1
docs/05_EDITOR_STYLE_GUIDE.md.