Список в Python (тип list) — упорядоченная коллекция, которую можно менять после создания. Создаётся квадратными скобками: cities = ["Москва", "Казань", "Пермь"]. К элементу обращаются по номеру с нуля: cities[0] вернёт «Москва». Добавить элемент можно методом append(), удалить через remove() или pop(), а отсортировать через sort().
Ниже собрано всё, что нужно новичку для работы со списками: создание, индексы, методы, перебор и пять ошибок, из-за которых код ведёт себя странно. Если вы только знакомитесь с языком, начните с основных команд Python, а потом возвращайтесь сюда. Тем, кто учит язык с нуля и хочет проверку домашних заданий, пригодятся курсы по Python с ценами и программами разных школ.
Что такое список в Python

В документации Python списки описаны как изменяемые последовательности, которые обычно хранят однотипные элементы. «Обычно» здесь важное слово: язык не запрещает положить в один список число, строку и другой список. Но на практике в списке хранят что-то одного рода: цены, имена, строки файла.
Три свойства, которые стоит запомнить сразу:
- порядок сохраняется: элементы лежат ровно в той последовательности, в которой вы их добавили;
- список изменяемый: элемент можно заменить, удалить или вставить без создания нового списка;
- повторы разрешены: «Казань» может встретиться в списке хоть три раза.
Новички часто путают список с кортежем, множеством и словарём. Вот чем они различаются:
| Тип | Как выглядит | Можно менять | Повторы | Когда брать |
|---|---|---|---|---|
Список list |
[1, 2, 3] |
да | да | набор данных, который будет расти и меняться |
Кортеж tuple |
(1, 2, 3) |
нет | да | неизменяемая запись: координаты, дата |
Множество set |
{1, 2, 3} |
да | нет | уникальные значения и быстрая проверка «есть ли элемент» |
Словарь dict |
{"a": 1} |
да | ключи уникальны | поиск значения по ключу |
Как создать список
Документация перечисляет четыре способа: пустые скобки [], скобки с элементами через запятую, генератор списка и функция list(). Генератор разберём ниже, остальные три покажем сразу:
cities = ["Москва", "Казань", "Пермь"]
mixed = [1, "два", 3.0, [4, 5]]
empty = []
letters = list("кот")
print(cities)
print(mixed)
print(empty, len(empty))
print(letters)
print(type(cities))
Результат:
['Москва', 'Казань', 'Пермь']
[1, 'два', 3.0, [4, 5]]
[] 0
['к', 'о', 'т']
<class 'list'>
Обратите внимание на list("кот"): функция разбивает строку на отдельные символы. Чтобы разрезать строку на слова, нужен метод split(), а не list(). Все варианты собраны в инструкции как преобразовать строку в список.
Как обратиться к элементу списка
У каждого элемента есть индекс, отсчёт идёт с нуля. Отрицательный индекс считает с конца: -1 вернёт последний элемент, -2 предпоследний. Через срез [1:3] можно взять кусок списка, а через присваивание по индексу заменить элемент.
cities = ["Москва", "Казань", "Пермь", "Омск"]
print(cities[0])
print(cities[-1])
print(cities[1:3])
cities[1] = "Самара"
print(cities)
print(cities[10])
Результат:
Москва
Омск
['Казань', 'Пермь']
['Москва', 'Самара', 'Пермь', 'Омск']
IndexError: list index out of range
Последняя строка упала с IndexError: в списке четыре элемента, а мы попросили одиннадцатый. Python не возвращает «пусто» и не подставляет None, он останавливает программу. Перед обращением по индексу, который пришёл извне, проверяйте длину через len().
У срезов есть шаг, отрицательные границы и пара неочевидных правил. Подробно они разобраны в отдельной статье про срезы в Python.
Методы списков: шпаргалка
Методы вызываются через точку: tasks.append("созвон"). Почти все они меняют сам список и ничего не возвращают. Это главный подвох, к нему вернёмся в разделе про ошибки.
| Метод | Что делает | Что возвращает |
|---|---|---|
append(x) |
добавляет элемент в конец | None |
extend(iterable) |
добавляет в конец все элементы другой коллекции | None |
insert(i, x) |
вставляет элемент на позицию i |
None |
remove(x) |
удаляет первое вхождение значения | None, если значения нет, то ValueError |
pop(i) |
удаляет элемент по индексу, без аргумента удаляет последний | удалённый элемент |
clear() |
очищает список | None |
index(x) |
ищет позицию первого вхождения | индекс, если значения нет, то ValueError |
count(x) |
считает, сколько раз встречается значение | число |
sort() |
сортирует на месте | None |
reverse() |
разворачивает порядок на месте | None |
copy() |
делает поверхностную копию | новый список |
Посмотрим, как список задач меняется после каждого вызова:
tasks = ["почта", "отчёт"]
tasks.append("созвон")
print(tasks)
tasks.insert(0, "кофе")
print(tasks)
tasks.extend(["код-ревью", "планёрка"])
print(tasks)
tasks.remove("почта")
print(tasks)
last = tasks.pop()
print(last, tasks)
del tasks[0]
print(tasks)
print(tasks.index("созвон"), tasks.count("отчёт"))
print("отчёт" in tasks)
Результат:
['почта', 'отчёт', 'созвон']
['кофе', 'почта', 'отчёт', 'созвон']
['кофе', 'почта', 'отчёт', 'созвон', 'код-ревью', 'планёрка']
['кофе', 'отчёт', 'созвон', 'код-ревью', 'планёрка']
планёрка ['кофе', 'отчёт', 'созвон', 'код-ревью']
['отчёт', 'созвон', 'код-ревью']
1 1
True
Разница между append() и extend() видна на третьей строке: extend() добавил два отдельных элемента, а append() с тем же аргументом вложил бы внутрь целый список. Подробнее о добавлении читайте в инструкции как добавить элемент в список, об удалении в статье про remove(), pop() и del.
Встроенные функции для списков
Кроме методов, со списками работают встроенные функции: len() считает элементы, sum() складывает числа, min() и max() находят крайние значения, sorted() возвращает отсортированную копию. Импортировать ничего не нужно.
prices = [490, 1290, 990, 250]
prices.sort()
print(prices)
print(sorted(prices, reverse=True))
print(prices.sort())
words = ["Яблоко", "банан", "Апельсин"]
print(sorted(words))
print(sorted(words, key=str.lower))
print(len(prices), sum(prices), min(prices), max(prices))
Результат:
[250, 490, 990, 1290]
[1290, 990, 490, 250]
None
['Апельсин', 'Яблоко', 'банан']
['Апельсин', 'банан', 'Яблоко']
4 3020 250 1290
Здесь три вещи, которые стоит разобрать:
sort()меняет сам список, аsorted()создаёт новый. Поэтомуprint(prices.sort())напечаталNone.- Строки сортируются по кодам символов, и заглавные буквы идут раньше строчных: «Яблоко» оказалось перед «банан». Аргумент
key=str.lowerсравнивает слова без учёта регистра. sum()работает только с числами. Для списка строк он упадёт сTypeError, строки склеивают через"".join().
Про сортировку по нескольким полям и параметр key подробно рассказано в статье sort() и sorted(). Сложение элементов с условием разобрано в инструкции как суммировать список, а случайный выбор элемента в материале про модуль random.
Перебор списка и генераторы списков
Чаще всего список обходят циклом for. Если кроме значения нужен номер, вместо счётчика берут enumerate():
cities = ["Москва", "Казань", "Пермь"]
for city in cities:
print(city)
for i, city in enumerate(cities, start=1):
print(i, city)
Результат:
Москва
Казань
Пермь
1 Москва
2 Казань
3 Пермь
Когда из одного списка нужно получить другой, удобнее генератор списка (list comprehension). По учебнику Python, это выражение в скобках, за которым идёт for и затем ноль или больше for или if. Одна строка заменяет цикл с append():
nums = [1, 2, 2, 3, 4]
odd = [n for n in nums if n % 2 != 0]
print(odd)
squares = [x * x for x in range(1, 6)]
print(squares)
Результат:
[1, 3]
[1, 4, 9, 16, 25]
Генератор хорош, пока он читается с первого раза. Если внутри два for и три условия, лучше вернуться к обычному циклу. Подробнее о нумерации читайте в статье про функцию enumerate(), а о цикле с условием в материале про цикл while.
Пять ошибок при работе со списками

Эти ошибки не выдают сообщений в терминале. Код отрабатывает, а данные оказываются не теми, что вы ждали.
1) Присваивание вместо копии
Строка b = a не копирует список. Она даёт второе имя тому же объекту, и изменение через b видно через a:
a = [1, 2, 3]
b = a
b.append(4)
print(a)
c = a.copy()
c.append(5)
print(a, c)
Результат:
[1, 2, 3, 4]
[1, 2, 3, 4] [1, 2, 3, 4, 5]
Решение: a.copy(), a[:] или list(a). Все три способа создают новый список.
2) Копия вложенного списка
copy() делает поверхностную копию: внешний список новый, а вложенные списки общие. В FAQ по программированию для общего случая советуют copy.copy() или copy.deepcopy(). Разницу видно на примере:
import copy
nested = [[1, 2], [3, 4]]
shallow = nested.copy()
deep = copy.deepcopy(nested)
nested[0].append(99)
print(shallow)
print(deep)
Результат:
[[1, 2, 99], [3, 4]]
[[1, 2], [3, 4]]
3) Таблица через умножение
Запись [[0] * 3] * 3 выглядит как таблица 3×3, но строки в ней одни и те же. В FAQ Python так и сказано: умножение через * не создаёт копий, оно размножает ссылки на один объект.
grid = [[0] * 3] * 3
grid[0][0] = 1
print(grid)
grid = [[0] * 3 for _ in range(3)]
grid[0][0] = 1
print(grid)
Результат:
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]
Решение: собирать строки генератором, как во второй половине примера. Тогда каждая строка создаётся заново.
4) Удаление элементов внутри цикла
Хотели убрать все чётные числа, а одна двойка осталась:
nums = [1, 2, 2, 3, 4]
for n in nums:
if n % 2 == 0:
nums.remove(n)
print(nums)
Результат:
[1, 2, 3]
После удаления первой двойки элементы сдвинулись влево, и цикл перешагнул через вторую. Учебник Python пишет, что в таких случаях обычно проще обходить копию коллекции или собрать новую.
Решение: [n for n in nums if n % 2 != 0], как в разделе про генераторы.
5) Список как значение по умолчанию
Функция должна каждый раз начинать с пустой корзины, а корзина копится между вызовами:
def add_item(item, basket=[]):
basket.append(item)
return basket
print(add_item("хлеб"))
print(add_item("молоко"))
def add_item_ok(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
print(add_item_ok("хлеб"))
print(add_item_ok("молоко"))
Результат:
['хлеб']
['хлеб', 'молоко']
['хлеб']
['молоко']
Причина описана в FAQ Python: значение по умолчанию создаётся один раз, когда функция определяется. Там же советуют ставить None и создавать список внутри функции, как в add_item_ok. Как устроены параметры функций, разобрано в инструкции про def.
Когда список лучше заменить

Список хорошо справляется с добавлением в конец и чтением по индексу. Но две операции у него медленные, обе отмечены в таблице сложности встроенных типов:
- проверка
x in списокперебирает элементы по очереди, это O(n); pop(0)иinsert(0, x)сдвигают все остальные элементы, в худшем случае это тоже O(n).
Мы замерили, как это выглядит в секундах. Список и множество по 100 000 чисел, ищем последний элемент 1000 раз. Очередь из 100 000 элементов, забираем первый 50 000 раз:
import timeit
from collections import deque
n = 100_000
data_list = list(range(n))
data_set = set(data_list)
t_list = timeit.timeit(lambda: (n - 1) in data_list, number=1000)
t_set = timeit.timeit(lambda: (n - 1) in data_set, number=1000)
print(f"in list: {t_list:.4f} с, in set: {t_set:.6f} с")
t_pop0 = timeit.timeit("l.pop(0)", setup="l = list(range(100_000))", number=50_000)
t_popleft = timeit.timeit("d.popleft()", setup="from collections import deque; d = deque(range(100_000))", number=50_000)
print(f"list.pop(0): {t_pop0:.4f} с, deque.popleft(): {t_popleft:.4f} с")
Результат на ноутбуке с Apple M4 Pro:
in list: 0.5449 с, in set: 0.000030 с
list.pop(0): 0.4362 с, deque.popleft(): 0.0005 с| Задача | Список | Что взять | Во сколько раз быстрее в замере |
|---|---|---|---|
| часто проверять «есть ли элемент» | около 0,54 с | set |
больше чем в 10 000 раз |
| забирать элементы из начала | около 0,44 с | collections.deque |
больше чем в 800 раз |
На вашем компьютере секунды будут другими, но разрыв останется большим: он следует из сложности самих операций. Учебник Python пишет, что для очереди список неэффективен, и предлагает вместо него deque. Если же порядок и повторы не важны, а важна быстрая проверка, переводите список в множество одной строкой: set(data).
Где освоить Python системно
Списки встречаются почти в каждой задаче на Python, и потренироваться на них проще всего на коротких упражнениях. Возьмите 30 задач для новичков и сверяйтесь со шпаргалкой методов выше, пока названия не запомнятся.
Если хочется программу с наставником и проверкой домашних заданий, сравните курсы по Python в каталоге: там видны цена, длительность и формат обучения у разных школ. Вот пять из них:
| Курс | Школа | Стоимость со скидкой | В рассрочку | Длительность | Обзор курса от Checkroi |
|---|---|---|---|---|---|
| Профессия «Python-разработчик» Перейти на сайт курса | 157 335 ₽ | 5987 ₽/мес. | 10 месяцев | Обзор курса | |
| Fullstack-разработчик на Python Перейти на сайт курса | 137 000 ₽ | 7125 ₽/мес. | 21 месяц | Обзор курса | |
| ДО Профессия Python-разработчик Перейти на сайт курса | 149 001 ₽ | 3167 ₽/мес. | 10 месяцев | Обзор курса | |
| Автоматизированное тестирование на Python Перейти на сайт курса | 122 226 ₽ | 4108 ₽/мес. | 9 месяцев | Обзор курса | |
| Профессия Python-разработчик Перейти на сайт курса | 140 040 ₽ | 4279 ₽/мес. | 10 месяцев | Обзор курса |
Больше программ — в полном каталоге курсов по Python




