
Списки (list) в Python: методы, функции и операции
Списки — один из самых важных контейнеров в Python: они динамические, изменяемые, поддерживают смешанные типы и вложенные структуры. В этой курсе вы разберёте создание и индексацию, срезы и генераторы списков, базовые операции и встроенные функции, полный справочник по методам (append, extend, insert, remove, pop, clear, index, count, sort, reverse, copy), а также типичные ошибки и мини-практикум. Поехали! 🚀
Что такое список (list)
Список — упорядоченная изменяемая коллекция: вы можете добавлять, удалять и заменять элементы на месте. Допускаются разные типы в одном списке (числа, строки, другие списки и словари), что удобно для быстрых прототипов и агрегации данных.
# примеры списков
empty = []
mix = [1, "a", 3.14, True]
nested = [[1, 2], [3, 4]] # вложенные списки
# динамичность — можно изменять на месте
mix[0] = 42
Важно помнить про «ссылочную» модель: переменная указывает на объект-список. Присваивание L2 = L1 не копирует, а даёт вторую ссылку на тот же самый список.
L1 = [1, 2, 3]
L2 = L1 # обе переменные указывают на один объект
L2.append(4)
print(L1) # [1, 2, 3, 4]
Создание списков
Четыре способа встречаются чаще всего: литералы [], конструктор list(), преобразование итерируемых, генераторы списков.
# литералы и list()
L1 = [1, 2, 3]
L2 = list("abc") # ['a','b','c']
L3 = list(range(5)) # [0,1,2,3,4]
# преобразования
tpl = (1, 2, 3); L4 = list(tpl)
set_items = {3, 1, 2}; L5 = list(set_items) # порядок не гарантируется
# генераторы списков (см. отдельный раздел ниже)
squares = [x*x for x in range(6)]
Будьте осторожны с умножением списков: выражение L = [[0]*3]*2 создаёт две ссылки на один и тот же вложенный список.
L = [[0]*3]*2
L[0][0] = 9
print(L) # [[9, 0, 0], [9, 0, 0]] — обе строки изменились
# правильный способ — генератор:
L = [[0]*3 for _ in range(2)]
Индексация и срезы
Индексы начинаются с нуля; поддерживаются отрицательные индексы (от конца). Срезы создают новые списки, а присваивание срезу изменяет исходный список сразу участками.
L = ["a","b","c","d","e"]
L[0], L[-1] # 'a', 'e'
L[1:4] # ['b','c','d']
L[:3], L[::2] # ['a','b','c']; ['a','c','e']
copy1 = L[:] # поверхностная копия
L[1:3] = ["B","C"] # замена среза: ['a','B','C','d','e']
Выход за границы (L[100]) вызывает IndexError; для безопасного доступа используйте проверку длины или try/except.
Базовые операции со списками
- len(L) — длина; in / not in — проверка принадлежности; + / * — конкатенация и повторение.
- Сравнение списков — лексикографическое по элементам (при совместимых типах).
nums = [1, 2, 3]
print(len(nums)) # 3
print(2 in nums) # True
print(nums + [4, 5]) # [1,2,3,4,5]
print(["a"]*3) # ['a','a','a']
Методы списков: справочник с примерами
Добавление элементов: append, extend, insert
append(x) добавляет один элемент в конец; extend(iterable) разворачивает итерируемый объект по элементам; insert(i, x) вставляет элемент на позицию.
L = [1, 2]
L.append(3) # [1,2,3]
L.extend([4, 5]) # [1,2,3,4,5]
L.insert(1, 100) # [1,100,2,3,4,5]
Ошибка новичков: append([4,5]) добавит один элемент-список, а не два элемента по отдельности.
L = [1, 2]; L.append([3, 4]) # [1, 2, [3, 4]]
Удаление/извлечение: remove, pop, clear
remove(x) удаляет первое вхождение x (ValueError, если нет элемента); pop(i=-1) извлекает и возвращает элемент по индексу (по умолчанию — последний); clear() очищает список.
L = ["a","b","b","c"]
L.remove("b") # ["a","b","c"] — удалилось первое вхождение
last = L.pop() # "c"; список стал ["a","b"]
first = L.pop(0) # "a"; список стал ["b"]
L.clear() # []
Поиск и подсчёт: index, count
index(x[, start[, end]]) — индекс первого вхождения; count(x) — количество вхождений.
L = [10, 20, 10, 30]
L.index(10) # 0
L.index(10, 1) # 2
L.count(10) # 2
Порядок элементов: sort, reverse
sort(key=None, reverse=False) сортирует на месте; reverse() переворачивает порядок; функция sorted(iterable, key=..., reverse=...) возвращает новый список, оставляя исходный без изменений.
L = ["Bob","alice","Carol"]
L.sort() # ['Bob','Carol','alice'] — по Unicode
L.sort(key=str.lower) # ['alice','Bob','Carol'] — без учёта регистра
L.reverse() # ['Carol','Bob','alice']
nums = [3,1,2]; print(sorted(nums)) # [1,2,3]
print(nums) # исходный не тронут
Копирование: copy
copy() и срез [:] делают поверхностную копию. Для вложенных структур используйте deepcopy из copy.
import copy
L = [[1],[2]]; shallow = L.copy(); deep = copy.deepcopy(L)
L[0].append(99)
print(shallow) # [[1, 99], [2]] — «зацепили» вложенный список
print(deep) # [[1], [2]] — независимая копия
Перебор и распаковка
Итерируйте элементы простым for, используйте enumerate для индексов, zip — для параллельного обхода. Распаковка удобна при присваивании и обмене значениями.
colors = ["red","green","blue"]
for c in colors: print(c)
for i, c in enumerate(colors, start=1): print(i, c)
xs = [1,2,3]; ys = [4,5,6]
for x, y in zip(xs, ys): print(x, y)
a, b = 1, 2; a, b = b, a # обмен без временной переменной
Генераторы списков (list comprehensions)
Компактный способ создать список из итерируемого источника, опционально с фильтром и преобразованием. Для сложной логики выбирайте обычный цикл ради читаемости.
# базовый шаблон
evens = [x for x in range(10) if x % 2 == 0]
pairs = [(x, y) for x in range(3) for y in range(2)]
# то же через цикл — нагляднее при сложных шагах
res = []
for x in range(10):
if x % 2 == 0: res.append(x)
Вложенные списки (матрицы)
«Список списков» удобен для представления таблиц. Доступ к элементу — по двум индексам; аккуратно копируйте и создавайте матрицы, чтобы не дублировать ссылки на один и тот же вложенный список.
M = [[1,2,3],[4,5,6]]
print(M[1][2]) # 6
# безопасное создание MxN нулями
rows, cols = 2, 3
M = [[0]*cols for _ in range(rows)]
Встроенные функции для списков
Помимо len и sorted, полезны sum, min, max, any, all. Параметр key даёт тонкий контроль сортировки.
nums = [3,5,1,4]
print(sum(nums), min(nums), max(nums)) # 13 1 5
print(any(n % 2 == 0 for n in nums)) # есть ли чётные
print(all(n > 0 for n in nums)) # все ли положительные
data = [{"n":"bob","age":30},{"n":"ann","age":20}]
print(sorted(data, key=lambda d: d["age"]))
Производительность и сложность
append работает амортизированно за O(1); вставка/удаление в середине — O(n). Частые операции «с головы» лучше делать через collections.deque. Большие «склейки» списков через + внутри цикла неэффективны — собирайте в список, а в конце объединяйте через extend или генератор.
Антипаттерны и частые ошибки
- Путаница append vs extend (элемент против «раскрытия» итерируемого).
- Копирование ссылок вместо объектов (L2 = L1 вместо L1.copy() / L1[:] / deepcopy).
- Умножение вложенных списков [[0]*N]*M с дублирующимися ссылками.
- Модификация списка во время итерации по нему: искажённые индексы и пропуски элементов.
- Неправильное сравнение: is вместо == для значений.
# безопасная модификация — по копии или через списковое включение
L = [1,2,3,4,5]
L = [x for x in L if x % 2 == 0] # фильтр без «прыгающих» индексов
Мини-практикум
Несколько задач для закрепления 👇
# 1) фильтр чётных и возведение в квадрат
nums = [1,2,3,4,5,6]
res = [n*n for n in nums if n % 2 == 0]; print(res) # [4,16,36]
# 2) разворачивание вложенного списка на один уровень
nested = [[1,2],[3,4,5]]
flat = [x for sub in nested for x in sub]; print(flat)
# 3) частоты элементов
data = ["a","b","a","c","b","a"]
freq = {}
for x in dаta: freq[x] = freq.get(x, 0) + 1
print(freq)
# 4) сортировка по ключу (второй элемент кортежа, по убыванию)
items = [("a",3),("b",1),("c",2)]
print(sorted(items, key=lambda t: t[1], reverse=True))
FAQ
Короткие ответы на частые вопросы о списках. Разворачивайте спойлеры с деталями и примерами 👇
append(x) добавляет один элемент (в том числе список как единый элемент), extend(iterable) перебирает итерируемый объект и добавляет его элементы. Нужен один объект — append; хотите «распаковать» — extend.
L = [1,2]; L.append([3,4]) # [1,2,[3,4]]
L = [1,2]; L.extend([3,4]) # [1,2,3,4]
list.sort() меняет список на месте и возвращает None; sorted(iterable) создаёт новый список, исходный не трогает. Нужна «быстрая» сортировка на месте — sort; важна неизменность входных данных — sorted.
Потому что копируется ссылка на один и тот же вложенный список. Изменения отражаются во всех «строках». Используйте генератор списков для независимых копий.
bad = [[0]*3]*2; bad[0][0] = 9; print(bad) # «дублирование»
good = [[0]*3 for _ in range(2)]
Для поверхностной копии — L.copy() или L[:]. Для глубокого копирования вложенных структур — copy.deepcopy.
Итерируйтесь по копии, собирайте результат в новый список или используйте списковое включение с фильтром.
list — изменяемый и динамический; tuple — неизменяемый, обычно легче и хешируемый (может быть ключом словаря, если элементы тоже хешируемы). Для «пакетов данных» без изменений — кортеж.
count(x) вернёт число вхождений; для множественных подсчётов используйте collections.Counter.
reverse() переворачивает на месте; срез L[::-1] создаёт перевёрнутую копию.
Итоги
Теперь вы уверенно создаёте списки, ориентируетесь в индексах и срезах, используете генераторы, знаете базовые операции и встроенные функции, а главное — владеете ключевыми методами (append, extend, insert, remove, pop, clear, index, count, sort, reverse, copy). Помните о мутабельности и ссылочной природе, избегайте антипаттернов (умножение вложенных, модификация «на лету»), и закрепляйте навыки короткими задачами — списки станут вашим универсальным рабочим инструментом 🙂