Списки в Python: что это такое и как с ними работать
Рассказали всё самое важное о списках для тех, кто только становится «змееустом».


Иллюстрация: Оля Ежак для Skillbox Media
Сегодня мы подробно поговорим о, пожалуй, самых важных объектах в Python — списках. Разберём, зачем они нужны, как их использовать и какие удобные функции есть для работы с ними.
В статье есть всё, что начинающим разработчикам нужно знать о списках в Python:
- Что это такое
- Как создавать списки в Python
- Какие с ними можно выполнять операции
- Как работать со встроенными функциями
- Какие в Python есть методы управления элементами
Что такое списки
Список (list) — это упорядоченный набор элементов, каждый из которых имеет свой номер, или индекс, позволяющий быстро получить к нему доступ. Нумерация элементов в списке начинается с 0: почему-то так сложилось в C, а C — это база. Теорий на этот счёт много — на «Хабре» даже вышло большое расследование :)

Иллюстрация: Оля Ежак для Skillbox Media
В одном списке одновременно могут лежать данные разных типов — например, и строки, и числа. А ещё в один список можно положить другой и ничего не сломается:

Иллюстрация: Оля Ежак для Skillbox Media
Все элементы в списке пронумерованы. Мы можем без проблем узнать индекс элемента и обратиться по нему.
Списки называют динамическими структурами данных, потому что их можно менять на ходу: удалить один или несколько элементов, заменить или добавить новые.

Иллюстрация: Оля Ежак для Skillbox Media
Когда мы создаём объект list, в памяти компьютера под него резервируется место. Нам не нужно переживать о том, сколько выделяется места и когда оно освобождается, — Python всё сделает сам. Например, когда мы добавляем новые элементы, он выделяет память, а когда удаляем старые — освобождает.
Под капотом списков в Python лежит структура данных под названием «массив». У массива есть два важных свойства: под каждый элемент он резервирует одинаковое количество памяти, а все элементы следуют друг за другом, без «пробелов».
Однако в списках Python можно хранить объекты разного размера и типа. Более того, размер массива ограничен, а размер списка в Python — нет. Но всё равно мы знаем, сколько у нас элементов, а значит, можем обратиться к любому из них с помощью индексов.
И тут есть небольшой трюк: списки в Python представляют собой массив ссылок. Да-да, решение очень элегантное — каждый элемент такого массива хранит не сами данные, а ссылку на их расположение в памяти компьютера!
Как создать список в Python
Чтобы создать объект list, в Python используют квадратные скобки — []. Внутри них перечисляют элементы через запятую:
a = [1, 2, 3]
Мы создали список a и поместили в него три числа, которые разделили запятыми. Давайте выведем его с помощью функции print():
print(a)
>>> [1, 2, 3]
Python выводит элементы в квадратных скобках, чтобы показать, что это list, а также ставит запятые между элементами.
Мы уже говорили, что списки могут хранить данные любого типа. В примере ниже объект b хранит: строку — cat, число — 123 и булево значение — True:
b = ['cat', 123, True]
print(b)
>>> ['cat', 123, True]
Также в Python можно создавать вложенные списки:
c = [1, 2, [3, 4]]
print(c)
>>> [1, 2, [3, 4]]
Мы получили объект, состоящий из двух чисел — 1 и 2 — и вложенного list с двумя элементами — [3, 4].
Читайте также:
Операции со списками
Если просто хранить данные в списках, то от них будет мало толку. Поэтому давайте рассмотрим, какие операции они позволяют выполнить.
Индексация
Доступ к элементам списка получают по индексам, через квадратные скобки []:
a = [1, 2, 3]
print(a[1])
>>> 2
Мы обратились ко второму элементу и вывели его с помощью print().
Здесь важно помнить две вещи:
- у каждого элемента есть свой индекс;
- индексы начинаются с 0.
Давайте ещё поиграем с индексами:
a = [1, 2, 3, 4]
a[0] # Обратится к 1
a[2] # Обратится к 3
a[3] # Обратится к 4
a[4] # Выведет ошибку
В последней строке мы обратились к несуществующему индексу, поэтому Python выдал ошибку.
Кроме того, Python поддерживает обращение к нескольким элементам сразу — через интервал. Делается это с помощью двоеточия — :.
a = [1, 2, 3, 4]
a[0:2] # Получим [1, 2]
Двоеточие позволяет получить срез списка. Полная форма оператора выглядит так: начальный_индекс:конечный_индекс:шаг.
Здесь мы указываем, с какого индекса начинается «срез», на каком заканчивается и с каким шагом берутся элементы — по умолчанию 1. Единственный нюанс с конечным индексом: хоть мы и можем подумать, что закончим именно на нём, на самом деле Python остановится на элементе с индексом конечный_индекс — 1. Почему создатели языка решили так сделать? Кто их знает.
В примере выше мы начали с индекса 0, а закончили на 1, потому что последний индекс не включается. Наш шаг был 1, то есть мы прошлись по каждому элементу.
Усложним пример:
a = [1, 2, 3, 4, 5]
a[1:6:2] # Получим [2, 4]
Здесь мы шли по элементам с шагом 2. Начали с индекса 1 — это первое число внутри скобок, а закончили на индексе 6, не включая его. Двигались с шагом 2, то есть через один элемент, и получили [2, 4].
Протестируйте этот тип индексации сами, чтобы лучше понять, как работают срезы в Python.
Изменение элементов
Списки — это динамическая структура данных. А значит, мы можем менять их уже после создания.
Например, можно заменить один элемент на другой:
a = [1, 2, 3]
a[1] = 4
print(a)
>>> [1, 4, 3]
Мы обратились к элементу по индексу и заменили его на число 4. Всё прошло успешно, список изменился.
Но нужно быть осторожными, потому что может случиться такое:
a = [1, 2]
b = a
a[0] = 5
print(a)
print(b)
>> [5, 2]
>> [5, 2]
Сначала мы создали список a с двумя элементами — 1 и 2. Затем объявили переменную b и присвоили ей содержимое a. Потом заменили первый элемент в a и… удивились, что он заменился и в b.
Проблема в том, что a — это ссылка на область в памяти компьютера, где хранится первый элемент списка, а также на следующий его элемент. Вот как всё это устроено в памяти компьютера:

Иллюстрация: Оля Ежак для Skillbox Media
Каждый элемент списка имеет четыре секции: свой адрес, данные, адрес следующего элемента и адрес предыдущего. Если мы получили доступ к какому-то элементу, мы без проблем можем двигаться вперёд-назад по этому списку и менять его данные.
Поэтому, когда мы присвоили списку b список a, то на самом деле присвоили ему ссылку на первый элемент — по сути, сделав их одним списком.
Объединение списков
Иногда полезно объединить два списка. Чтобы это сделать, используют оператор +:
a = [1, 2]
b = [3, 4]
с = a + b
print(с)
>>> [1, 2, 3, 4]
Мы создали два списка — a и b. Затем переприсвоили a новым списком, который стал объединением старого a и b.
Разложение списка
Элементы списка можно присвоить отдельным переменным:
a = [1, 2, 3]
d1, d2, d3 = a
print(d1)
print(d2)
print(d3)
>>> 1
>>> 2
>>> 3
Здесь из списка a поочерёдно достаются элементы, начиная с индекса 0, и присваиваются переменным. И в отличие от присвоения одного списка другому, в этом случае Python создаст три отдельных целых числа, которые никак не будут связаны с элементами списка, и присвоит их трём переменным. Поэтому, если мы изменим, например, переменную d2, со списком a ничего не случится.
Перебор элементов
Мы можем перебирать элементы списка с помощью циклов for и while.
Так выглядит перебор через for:
animals = ['cat', 'dog', 'bat']
for animal in animals:
print(animal)
>>> cat
>>> dog
>>> bat
Здесь мы перебираем каждый элемент списка и выводим их с помощью функции print().
А вот так выглядит перебор через цикл while:
animals = ['cat', 'dog', 'bat']
i = 0
while i < len(animals):
print(animals[i])
i += 1
>>> cat
>>> dog
>>> bat
Этот перебор чуть сложнее, потому что мы используем дополнительную переменную i, чтобы обращаться к элементам списка. Также мы использовали встроенную функцию len(), чтобы узнать размер нашего списка. А ещё в условии цикла while мы указали знак «меньше» (<), потому что индексация элементов идёт до значения количество элементов списка — 1. Как и в прошлом примере, все элементы по очереди выводятся с помощью функции print().
Сравнение списков
Python поддерживает сравнение списков. Два списка считаются равными, если они содержат одинаковые элементы. Функция возвращает булево значение — True или False:
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
>>> True
Получили, что списки равны.
В некоторых языках равенство ещё проверяется и по тому, ссылаются ли переменные на один и тот же объект. Обычно это делается через оператор ===. В Python это можно сделать через оператор is, который проверяет, имеют ли две переменные один и тот же адрес в памяти:
a = [1, 2, 3]
b = a
print(a is b)
>>> True
Получили, что две переменные ссылаются на один и тот же адрес в памяти.
Встроенные функции для списков Python
В Python есть четыре функции, которые позволяют узнавать длину списка, сортировать его и возвращать максимальное и минимальное значение.
len()
Возвращает длину списка:
a = [5, 3, 1]
len(a) # 3
sorted()
Возвращает отсортированный список:
a = [8, 1, 3, 2]
sorted(a) # [1, 2, 3, 8]
min() и max()
Возвращают наименьший и наибольший элемент списка:
a = [1, 9, -2, 3]
min(a) # -2
max(a) # 9
Методы списков Python
Чтобы проще управлять элементами списка, в стандартной библиотеке Python есть набор популярных методов для списков. Разберём основные из них.
append()
Добавляет новый элемент в конец списка:
a = [1, 2, 3]
a.append(4)
print(a)
>>> [1, 2, 3, 4]
extend()
Добавляет набор элементов в конец списка:
a = [1, 2, 3]
a.extend([4, 5])
print(a)
>>> [1, 2, 3, 4, 5]
Внутрь метода extend() нужно передать итерируемый объект — например, другой list или строку.
Вот так метод extend() добавит строку:
a = ['cat', 'dog', 'bat']
a.extend('mouse')
print(a)
>>> ['cat', 'dog', 'bat', 'm', 'o', 'u', 's', 'e']
Заметьте, что строка добавилась посимвольно.
insert()
Добавляет новый элемент по индексу:
a = [1, 2, 3]
a.insert(0, 4)
print(a)
>>> [4, 1, 2, 3]
Сначала мы передаём индекс, по которому хотим вставить новый элемент, а затем сам элемент.
remove()
Удаляет элемент из списка:
a = [1, 2, 3, 1]
a.remove(1)
print(a)
>>> [2, 3, 1]
Метод удаляет только первое вхождение элемента. Остальные остаются нетронутыми.
Если элемента нет в списке, Python вернёт ошибку и программа прервётся:
a = [1, 2, 3, 1]
a.remove(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
Ошибка говорит, что элемента нет в списке.
Читайте также:
clear()
Удаляет все элементы из списка и делает его пустым:
a = [1, 2, 3]
a.clear()
print(a)
>>> []
index()
Возвращает индекс элемента списка в Python:
a = [1, 2, 3]
print(a.index(2))
>>> 1
Если элемента нет в списке, выведется ошибка:
a = [1, 2, 3]
print(a.index(4))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 4 is not in list
pop()
Удаляет элемент по индексу и возвращает его как результат:
a = [1, 2, 3]
print(a.pop())
print(a)
>>> 3
>>> [1, 2]
Мы не передали индекс в метод, поэтому он удалил последний элемент списка. Если передать индекс, то получится так:
a = [1, 2, 3]
print(a.pop(1))
print(a)
>>> 2
>>> [1, 3]
count()
Считает, сколько раз элемент повторяется в списке:
a = [1, 1, 1, 2]
print(a.count(1))
>>> 3
sort()
Сортирует список:
a = [4, 1, 5, 2]
a.sort() # [1, 2, 4, 5]
Если нам нужно отсортировать в обратном порядке — от большего к меньшему, — в методе есть дополнительный параметр reverse:
a = [4, 1, 5, 2]
a.sort(reverse=True) # [5, 4, 2, 1]
reverse()
Переставляет элементы в обратном порядке:
a = [1, 3, 2, 4]
a.reverse() # [4, 2, 3, 1]
copy()
Копирует список:
a = [1, 2, 3]
b = a.copy()
print(b)
>>> [1, 2, 3]
Для того чтобы быстро находить нужные методы во время работы, пользуйтесь этой шпаргалкой:
Метод | Что делает |
---|---|
a.append(x) | Добавляет элемент x в конец списка a. Если x — список, то он появится в a как вложенный |
a.extend(b) | Добавляет в конец a все элементы списка b |
a.insert(i, x) | Вставляет элемент x на позицию i |
a.remove(x) | Удаляет в a первый элемент, значение которого равно x |
a.clear() | Удаляет все элементы из списка a и делает его пустым |
a.index(x) | Возвращает индекс элемента списка |
a.pop(i) | Удаляет элемент по индексу и возвращает его |
a.count(x) | Считает, сколько раз элемент повторяется в списке |
a.sort() | Сортирует список. Чтобы отсортировать элементы в обратном порядке, нужно установить дополнительный аргумент reverse=True |
a.reverse() | Возвращает обратный итератор списка a |
a.copy() | Создаёт поверхностную копию списка. Для создания глубокой копии используйте метод deepcopy из модуля copy |
Что запомнить
Лучше не учить это всё, а применять на практике. А ещё лучше — попытаться написать каждый метод самостоятельно, не используя никакие встроенные функции.
Сколько бы вы ни писали код на Python, всё равно придётся подсматривать в документацию и понимать, какой метод что делает. И для этого есть разные удобные сайты — например, полный список методов можно посмотреть на W3Schools.
Больше интересного про код в нашем телеграм-канале. Подписывайтесь!