Списки в Python: создание, методы и частые ошибки с примерами

Список в Python создаётся квадратными скобками, а элементы читаются по индексу с нуля.

В статье шпаргалка по 11 методам list, функции len, sum и sorted, генераторы списков и пять ошибок, из-за которых данные меняются не там, где вы ждали.

В конце замер, во сколько раз set и deque обгоняют список на поиске элемента и на очереди.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3090 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3744 экспертных мнения Подписаться на Телеграм-канал
Обложка: Списки в Python: создание, методы и частые ошибки с примерами

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

Ниже собрано всё, что нужно новичку для работы со списками: создание, индексы, методы, перебор и пять ошибок, из-за которых код ведёт себя странно. Если вы только знакомитесь с языком, начните с основных команд Python, а потом возвращайтесь сюда. Тем, кто учит язык с нуля и хочет проверку домашних заданий, пригодятся курсы по Python с ценами и программами разных школ.

CheckroiCheckroiПодборка курсов по Python568 курсов • 51 школаСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Что такое список в 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(). Все варианты собраны в инструкции как преобразовать строку в список.

Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Как обратиться к элементу списка

У каждого элемента есть индекс, отсчёт идёт с нуля. Отрицательный индекс считает с конца: -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

Здесь три вещи, которые стоит разобрать:

  1. sort() меняет сам список, а sorted() создаёт новый. Поэтому print(prices.sort()) напечатал None.
  2. Строки сортируются по кодам символов, и заглавные буквы идут раньше строчных: «Яблоко» оказалось перед «банан». Аргумент key=str.lower сравнивает слова без учёта регистра.
  3. 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.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Пять ошибок при работе со списками

Рой радуется, найдя ошибку в коде с помощью лупы

Эти ошибки не выдают сообщений в терминале. Код отрабатывает, а данные оказываются не теми, что вы ждали.

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-разработчик»
Перейти на сайт курса
SkillboxSkillbox157 335 ₽5987 ₽/мес.10 месяцевОбзор курса
Fullstack-разработчик на Python
Перейти на сайт курса
НетологияНетология137 000 ₽7125 ₽/мес.21 месяцОбзор курса
ДО Профессия Python-разработчик
Перейти на сайт курса
GeekBrainsGeekBrains149 001 ₽3167 ₽/мес.10 месяцевОбзор курса
Автоматизированное тестирование на Python
Перейти на сайт курса
SkillboxSkillbox122 226 ₽4108 ₽/мес.9 месяцевОбзор курса
Профессия Python-разработчик
Перейти на сайт курса
SkillFactorySkillFactory140 040 ₽4279 ₽/мес.10 месяцевОбзор курса

Больше программ — в полном каталоге курсов по Python

Часто задаваемые вопросы

Чем список отличается от кортежа в Python?

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

Как создать пустой список в Python?

Двумя способами: items = [] или items = list(). Результат одинаковый, первая запись короче.

Как узнать длину списка?

Функцией len(): len([490, 1290, 990]) вернёт 3. Для пустого списка она вернёт 0.

Можно ли хранить в одном списке разные типы данных?

Можно: [1, "два", 3.0, [4, 5]] работает без ошибок. Но обычно в списке хранят однотипные элементы, так их проще обрабатывать в цикле и сортировать.

Как скопировать список, чтобы не менять оригинал?

Подойдёт a.copy(), a[:] или list(a). Если внутри есть вложенные списки, нужна глубокая копия: copy.deepcopy(a) из модуля copy. Запись b = a копию не создаёт.

Почему sort() возвращает None?

Метод сортирует список на месте и ничего не возвращает. В документации Python это объясняют так: возврат None напоминает, что метод работает через побочный эффект. Если нужна отсортированная копия, используйте sorted().

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!