Модуль 3 · Списки и циклы

Справочник по Python · модуль 3 · списки и циклы

Глава 3.1

3.1

Коллекции в Python

Коллекция хранит группу значений под одним именем. Выбор между списком, кортежем, множеством и словарём зависит от того, важны ли порядок, изменение, уникальность и обращение по ключу.

Категория
Структуры данных
Уровень
Начальный
Связанные темы
Типы данных, for, индексы
Зачем это знать
Хранить и обрабатывать группы значений

§1Зачем нужны коллекции

Пока значений два-три, хватает обычных переменных. Но задача «сохранить температуру за неделю» на отдельных переменных выглядит так:

main.pyсемь имён для одних данных
temperature_1 = 18
temperature_2 = 21
temperature_3 = 17
# ...и так далее

Такой код невозможно обработать циклом, нельзя посчитать среднее одной строкой и нельзя расширить до тридцати дней, не переписав всю программу. Коллекция решает это одним именем:

main.pyодно имя на все значения
temperatures = [18, 21, 17, 23]

print(sum(temperatures))
print(max(temperatures))
Выводсумма и максимум
79
23

Количество значений при этом больше не влияет на длину кода: те же две строки работают и для четырёх, и для тысячи измерений.

§2Что такое коллекция

Коллекция — структура для хранения нескольких элементов. С коллекцией можно добавлять и удалять значения, искать их, изменять и перебирать циклом — конкретные возможности зависят от её типа.

Схемаодно имя — группа данных
одно значение:   temperature  = 18
группа значений: temperatures = [18, 21, 17, 23]

Имя коллекции по традиции ставят во множественное число: temperatures, names, prices. Это сразу подсказывает читателю кода, что внутри не одно значение.

§3Четыре основных вида

ТипЗаписьГлавная особенность
list[10, 20, 30]упорядоченный изменяемый список
tuple(10, 20, 30)упорядоченная неизменяемая последовательность
set{10, 20, 30}неупорядоченный набор уникальных элементов
dict{"name": "Alex"}пары «ключ — значение»

Скобки различаются: квадратные у списка, круглые у кортежа, фигурные у множества и словаря. Дополнительные структуры, например deque и namedtuple, находятся в стандартной библиотеке и изучаются после основных коллекций.

Основной инструмент начинающего — список. Дальше в главе разбирается прежде всего он.

§4Список и индексы

Список — упорядоченная изменяемая коллекция. Каждый элемент занимает позицию с числовым индексом, а первый индекс равен нулю.

Схеманулевая индексация
numbers = [10, 20, 30, 40]
индекс:     0   1   2   3

Индекс — это не номер по счёту, а смещение от начала. Поэтому третий по счёту элемент лежит под индексом 2.

main.pyдоступ по индексу
numbers = [10, 20, 30, 40]

print(numbers[0])
print(numbers[2])
Выводпервый и третий элементы
10
30
Список из четырёх — индексы до трёх

Последний допустимый индекс всегда на единицу меньше количества элементов. Обращение к numbers[4] здесь вызовет IndexError.

§5Отрицательные индексы

Python умеет отсчитывать позиции с конца. Индекс -1 означает последний элемент, -2 — предпоследний.

Схемадва способа адресовать одну ячейку
letters   = [ "a",  "b",  "c",  "d" ]
слева:         0     1     2     3
справа:       -4    -3    -2    -1
main.pyпоследний и предпоследний
letters = ["a", "b", "c", "d"]

print(letters[-1])
print(letters[-2])
Выводотсчёт с конца
d
c

Это избавляет от вычислений вида «длина минус один» там, где нужен просто последний элемент. Нуля с минусом не существует: -0 — это тот же 0, то есть первый элемент.

§6len(): длина коллекции

len() — встроенная функция, которая возвращает количество элементов. Она понадобится почти в каждой задаче с коллекциями.

main.pyколичество и последний элемент
temperatures = [18, 21, 17, 23]

print(len(temperatures))
print(temperatures[len(temperatures) - 1])
Выводчетыре элемента, последний равен 23
4
23

У пустого списка [] длина равна 0, и обращаться по любому индексу к нему нельзя. Проверка if len(items) > 0 — стандартный способ убедиться, что данные вообще есть.

§7Изменение списка

Элемент списка можно заменить по индексу. Сам список после этого остаётся той же коллекцией, но его содержимое меняется.

main.pyзамена второго элемента
numbers = [10, 20, 30]
numbers[1] = 50
print(numbers)
Выводсписок изменён
[10, 50, 30]

Слева от знака = запись numbers[1] означает не «взять значение», а «указать ячейку для записи». Подробно этот механизм разбирается в главе 3.6.

§8Перебор циклом

Главная причина складывать данные в коллекцию — возможность обработать их одним циклом, независимо от количества. Сам цикл подробно разбирается в главах 3.2–3.4; здесь достаточно увидеть, ради чего он нужен.

main.pyкаждый элемент по очереди
temperatures = [18, 21, 17, 23]

for temperature in temperatures:
    print(temperature)
Выводчетыре повтора
18
21
17
23

Переменная цикла получает значение очередного элемента. Имя для неё берут в единственном числе — temperature при списке temperatures, — и код читается как фраза: «для каждой температуры из температур».

Если нужны не значения, а позиции, используют форму for index in range(len(items)) — ей посвящена глава 3.6.

§9Порядок и доступ

КоллекцияПорядокКак обращаются к элементу
list, tuple, strпозиции идут последовательнопо числовому индексу
dictсохраняет порядок добавленияпо ключу, а не по позиции
setпорядок не предназначен для позиционного доступаобычного индекса нет

У словаря порядок добавления сохраняется, но запись dictionary[0] означает поиск ключа 0, а не первого элемента. У множества индексов нет вовсе: {1, 2, 3}[0] вызовет TypeError.

§10Изменяемость

Изменяемые коллекции можно обновлять после создания. Неизменяемые нельзя менять по частям — для другого содержимого создают новый объект.

ИзменяемыеНеизменяемые
list, dict, set, dequetuple, str, frozenset
main.pyкортеж читается, но не меняется
point = (10, 20)
print(point[0])

# point[0] = 5  →  TypeError
Выводчтение разрешено
10

Неизменяемость — не ограничение, а гарантия. Кортеж уместен там, где данные не должны меняться случайно: координаты точки, дата, пара «широта и долгота».

§11Разные типы элементов

Список может хранить значения разных типов одновременно.

main.pyсмешанный список
data = [10, "Python", True, 3.14]
print(data)
Выводтипы сохранены
[10, 'Python', True, 3.14]

Это допустимо, но однородный список обычно проще обрабатывать: все температуры или все имена можно передать в sum() или отсортировать, а смешанный — нет.

Исключение — записи, где позиции имеют разный смысл: ["Иванов", 17, True]. Для таких данных обычно лучше подходят словарь или кортеж.

§12Вложенные коллекции

Элементом списка может быть другая коллекция. Так представляют таблицы и составные записи.

main.pyсписок строк матрицы
matrix = [
    [1, 2],
    [3, 4]
]

print(len(matrix))
print(matrix[1])
Выводдва элемента, второй — список
2
[3, 4]

Длина внешнего списка равна 2: в нём лежат не четыре числа, а два списка. Запись matrix[1] даёт целую строку таблицы.

Чтобы добраться до конкретного числа, к результату применяют индекс ещё раз. Двойные скобки читаются слева направо:

Схемадва шага в одной записи
matrix[1][0]
      │  └ ② из полученного списка [3, 4] взять элемент 0 → 3
      └ ① из matrix взять элемент 1 → [3, 4]
main.pyто же самое в два шага
row = matrix[1]
print(row[0])
print(matrix[1][0])
Выводобе записи равнозначны
3
3

Первый индекс выбирает строку, второй — позицию внутри неё. Такой порядок сохраняется и на большей глубине вложенности.

§13Строка как последовательность

Строка тоже упорядоченная коллекция — из символов. К ней применимы индексы, отрицательные индексы, len() и перебор циклом.

main.pyстрока ведёт себя как список символов
word = "Python"

print(word[0])
print(word[-1])
print(len(word))
Выводпервый символ, последний, длина
P
n
6

Отличие одно, но важное: строка неизменяема. Запись word[0] = "J" вызовет TypeError — вместо изменения создают новую строку.

§14Как выбрать коллекцию

Что нужноПодходящий тип
хранить значения по порядку и менять ихlist
защитить набор от измененийtuple
убрать повторы, быстро проверять наличиеset
находить значение по имени или кодуdict

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

§15Частые ошибки

Что написаноЧто произойдётКак правильно
numbers[1] называют первым элементомбудет взят второй элементпомнить, что первый индекс равен 0
numbers[4] для списка из четырёх элементовIndexErrorиспользовать индексы от 0 до 3
numbers[len(numbers)]IndexError: длина на единицу больше последнего индексаnumbers[len(numbers) - 1] или numbers[-1]
point[0] = 5 для кортежаTypeError: кортеж неизменяемсоздать новый кортеж или выбрать список
numbers.len()AttributeError: это функция, а не методlen(numbers)
matrix[1, 0] для вложенного спискаTypeErrormatrix[1][0]
ожидать постоянный порядок множествавывод может идти не в порядке добавленияне использовать set для позиционных данных
{} считают пустым множествомсоздастся пустой словарьдля пустого множества писать set()

§16Проверьте себя

Как получить первый элемент списка items?

items[0], потому что индексация начинается с нуля.

Как получить последний элемент, не зная длины?

items[-1]. Отрицательные индексы отсчитывают позиции с конца.

Чему равна len(matrix) для [[1, 2], [3, 4]]?

2: во внешнем списке два элемента, и каждый из них — список.

Что означает запись matrix[1][0]?

Сначала из matrix берётся элемент с индексом 1, а затем из полученного списка — элемент с индексом 0.

Какая коллекция хранит только уникальные элементы?

Множество set.

Можно ли заменить элемент кортежа по индексу?

Нет. Кортеж неизменяем; для другого содержимого нужно создать новый кортеж.

§17Шпаргалка

Список[1, 2, 3]
Кортеж(1, 2, 3)
Множество{1, 2, 3}
Словарь{"key": "value"}
Первый и последнийitems[0]items[-1]
Количествоlen(items)
Вложенный элементmatrix[1][0]
Переборfor item in items:

Итог главы

Коллекции хранят группы данных под одним именем и потому позволяют обрабатывать любое количество значений одним циклом. Список изменяем и поддерживает доступ по позиции, кортеж неизменяем, множество хранит уникальные элементы, а словарь связывает ключи со значениями. Индексы начинаются с нуля, отрицательные отсчитывают с конца, а len() даёт количество элементов.

Глава 3.1 · Коллекции в Python · Справочник по Python Автор: Макаров Максим Николаевич