← назад к разделу

Почти любая программа на бэкенде — это перекладывание данных из одной коллекции в другую: собрать список заказов, сгруппировать их по клиенту, отфильтровать оплаченные. Python даёт четыре базовые структуры данных, и большая часть повседневного кода держится именно на них. Разберём, когда что брать и какими приёмами их удобно обрабатывать.

Четыре базовые структуры: когда что

У Python есть четыре встроенные коллекции, и выбор между ними — это первое решение, которое вы принимаете, держа данные в памяти.

list — упорядоченный изменяемый список. Это рабочая лошадка: элементы идут по порядку, их можно добавлять, удалять и менять на месте. Берите list, когда порядок важен и набор будет меняться.

orders = ["a-1", "a-2", "a-3"]
orders.append("a-4")   # добавили в конец
orders[0] = "a-0"      # поменяли элемент на месте

tuple — упорядоченный, но неизменяемый набор. После создания его нельзя поменять. Кортеж берут для фиксированной записи из нескольких полей (например, пара «широта, долгота») и там, где важно, что данные не «поедут».

point = (55.75, 37.62)   # координаты, менять не нужно
# point[0] = 0           # ошибка: tuple неизменяем

Короткая формула: list — для однородной коллекции, которая растёт; tuple — для фиксированной записи из разнородных полей.

dict — словарь, набор пар «ключ → значение». Главный инструмент, когда нужно находить данные по ключу, а не перебирать всё подряд. Поиск по ключу быстрый и не зависит от размера словаря.

prices = {"apple": 50, "bread": 30}
prices["milk"] = 70          # добавили пару
print(prices["apple"])       # быстрый доступ по ключу → 50
print(prices.get("eggs", 0)) # get с значением по умолчанию, без ошибки

set — множество уникальных элементов без порядка. Берут, чтобы убрать дубликаты или быстро проверить «есть ли элемент в наборе».

seen = {"a", "b", "a"}   # дубликат отбросится → {"a", "b"}
print("a" in seen)        # быстрая проверка вхождения → True
unique = set([1, 2, 2, 3])  # убрать дубликаты из списка → {1, 2, 3}

Ключи dict и элементы set должны быть хешируемыми — то есть неизменяемыми. Строка, число, tuple подойдут как ключ; list — нет. Если нужно неизменяемое множество (например, как ключ словаря), есть frozenset.

Срезы (slicing)

Срез — это способ взять кусок последовательности (list, tuple, строки) по синтаксису [start:stop:step]. Граница start включается, stop — нет.

nums = [0, 1, 2, 3, 4, 5]
print(nums[1:4])    # с 1-го по 3-й → [1, 2, 3]
print(nums[:3])     # первые три → [0, 1, 2]
print(nums[3:])     # с 3-го до конца → [3, 4, 5]
print(nums[::2])    # каждый второй → [0, 2, 4]
print(nums[::-1])   # развернуть → [5, 4, 3, 2, 1, 0]

Отрицательные индексы считают с конца: nums[-1] — последний элемент, nums[-2:] — два последних. Срез списка возвращает новый список, исходный не меняется.

Comprehensions

Comprehension — это компактный способ построить коллекцию из другой одной строкой, вместо цикла с append. Это одна из самых узнаваемых черт Python.

Списковое (list comprehension) — собрать новый список:

nums = [1, 2, 3, 4, 5]
squares = [n * n for n in nums]            # [1, 4, 9, 16, 25]
evens = [n for n in nums if n % 2 == 0]    # с фильтром → [2, 4]

Читается слева направо как фраза: «возьми n * n для каждого n из nums». Условие if в конце оставляет только подходящие элементы.

Словарное (dict comprehension) — построить словарь:

prices = {"apple": 50, "bread": 30}
# поднять цены на 10%
updated = {name: price * 1.1 for name, price in prices.items()}

Множественное (set comprehension) — собрать множество уникальных значений:

words = ["aa", "bb", "aa", "ccc"]
lengths = {len(w) for w in words}   # уникальные длины → {2, 3}

Comprehension хорош для простых преобразований. Если внутри появляется сложная логика в несколько действий — лучше вернуться к обычному циклу, так читается понятнее.

Распаковка (unpacking)

Распаковка позволяет «разложить» коллекцию по нескольким переменным за одно присваивание.

point = (55.75, 37.62)
lat, lon = point        # lat = 55.75, lon = 37.62

Звёздочка * собирает «остаток» в список — удобно, когда часть элементов нужна по отдельности, а часть скопом:

first, *rest = [1, 2, 3, 4]   # first = 1, rest = [2, 3, 4]
*head, last = [1, 2, 3, 4]    # head = [1, 2, 3], last = 4

Распаковка словаря через ** пригодится, чтобы слить два словаря или передать набор именованных аргументов:

defaults = {"host": "localhost", "port": 5432}
override = {"port": 6432}
config = {**defaults, **override}   # {"host": "localhost", "port": 6432}

Распаковка же стоит за обменом значениями без временной переменной:

a, b = 1, 2
a, b = b, a   # теперь a = 2, b = 1

Сортировка и ключи

Функция sorted возвращает новый отсортированный список, а метод list.sort() сортирует список на месте. Для случайного набора берите sorted — он не портит исходные данные.

nums = [3, 1, 2]
print(sorted(nums))        # [1, 2, 3], nums не изменился
print(sorted(nums, reverse=True))  # по убыванию → [3, 2, 1]

Самое полезное — параметр key: функция, которая для каждого элемента возвращает значение, по которому сравнивать. Так сортируют объекты по нужному полю.

orders = [
    {"id": "a", "total": 300},
    {"id": "b", "total": 100},
    {"id": "c", "total": 200},
]
by_total = sorted(orders, key=lambda o: o["total"])
# отсортировано по сумме: b (100), c (200), a (300)

Если ключ возвращает tuple, сортировка идёт по нескольким полям по очереди — сначала по первому, при равенстве по второму:

people = [("Ann", 30), ("Bob", 25), ("Ann", 25)]
# сначала по имени, потом по возрасту
print(sorted(people, key=lambda p: (p[0], p[1])))
# [("Ann", 25), ("Ann", 30), ("Bob", 25)]

Базовые приёмы работы с коллекциями

Несколько идиом, которые встречаются постоянно.

Перебор с индексомenumerate вместо ручного счётчика:

for i, name in enumerate(["a", "b", "c"]):
    print(i, name)   # 0 a / 1 b / 2 c

Параллельный перебор двух списковzip склеивает их по позициям:

names = ["apple", "bread"]
prices = [50, 30]
catalog = dict(zip(names, prices))   # {"apple": 50, "bread": 30}

Проверка вхождения — оператор in. Для set и dict это быстро независимо от размера, для list — перебором, поэтому для частых проверок «есть ли элемент» выбирайте set.

Группировка/подсчёт — словарь как накопитель:

words = ["a", "b", "a", "a", "b"]
counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1   # {"a": 3, "b": 2}

Коротко

  • list — упорядоченный изменяемый список; tuple — неизменяемая фиксированная запись; dict — быстрый поиск по ключу; set — уникальные элементы и быстрая проверка вхождения.
  • Ключи dict и элементы set должны быть хешируемыми (неизменяемыми): строка, число, tuple — да; list — нет.
  • Срезы [start:stop:step] берут кусок последовательности; stop не включается, отрицательный шаг разворачивает.
  • Comprehensions строят list/dict/set одной строкой; для сложной логики возвращайтесь к обычному циклу.
  • Распаковка раскладывает коллекции по переменным; * собирает остаток, ** сливает словари.
  • sorted возвращает новый список; параметр key задаёт поле сортировки, tuple в ключе — сортировку по нескольким полям.
  • enumerate, zip, in и словарь-накопитель — повседневные идиомы обработки коллекций.

Что почитать дальше

  • Синтаксис и типы Python — базовые типы, на которых строятся коллекции.
  • Функции и модули — lambda, аргументы и как раскладывать код по файлам.
  • Итераторы и генераторы — как перебор коллекций работает изнутри и как обрабатывать данные лениво.