Списки

Теория

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

Главное отличие от строки: список изменяемый. Элементы можно заменять, добавлять и удалять, и всё это меняет тот же самый список. Поэтому методы списка (append, remove, sort…) работают «на месте» и возвращают None — в отличие от методов строк, которые возвращают новую строку. Перепутать эти два поведения — одна из самых частых ошибок новичков.

Наглядно

Таблица 1. Основные операции со списком cart = ["мышь", "клавиатура"]. Обратите внимание на последний столбец: меняет ли операция сам список.

Операция Пример Результат Меняет cart?
элемент по индексу cart[0], cart[-1] "мышь", "клавиатура" нет
длина, проверка len(cart), "мышь" in cart 2, True нет
срез cart[:1] ["мышь"] — новый список нет
замена элемента cart[1] = "коврик" — да
добавить в конец cart.append("кабель") возвращает None да
вставить по индексу cart.insert(0, "наушники") возвращает None да
добавить несколько cart.extend(["коврик", "кабель"]) возвращает None да
удалить по индексу cart.pop(), cart.pop(0) удалённый элемент да
удалить по значению cart.remove("мышь") None; только первое вхождение да
склейка cart + ["коврик"] новый список нет

На практике

Задача: вести корзину покупателя — добавлять и убирать товары, менять позиции, считать сумму.

Шаг 1. Создаём список и читаем элементы

Корзина — список названий товаров:

python
cart = ["мышь", "клавиатура"]
print(cart[0], cart[-1], len(cart))
print("мышь" in cart, "монитор" in cart)

Результат:

вывод
мышь клавиатура 2
True False

Шаг 2. Заменяем элемент

Покупатель выбрал механическую клавиатуру вместо обычной — меняем элемент по индексу:

python
cart[1] = "механическая клавиатура"
print(cart)

Результат:

вывод
['мышь', 'механическая клавиатура']

Со строкой так нельзя (TypeError), со списком — можно: он изменяемый.

Шаг 3. Добавляем товары

append добавляет один элемент в конец, insert — по индексу, extend — все элементы другого списка:

python
cart.append("коврик")
cart.insert(0, "наушники")
cart.extend(["кабель", "подставка"])
print(cart)

Результат:

вывод
['наушники', 'мышь', 'механическая клавиатура', 'коврик', 'кабель', 'подставка']

Шаг 4. Убираем товары

pop удаляет по индексу и возвращает удалённое, remove — по значению:

python
last = cart.pop()
first = cart.pop(0)
cart.remove("коврик")
print(last, first)
print(cart)

Результат:

вывод
подставка наушники
['мышь', 'механическая клавиатура', 'кабель']

Если значения в списке нет, remove падает:

python
cart.remove("монитор")

Результат:

вывод
ValueError: list.remove(x): x not in list

Шаг 5. Помним, что методы возвращают None

Методы, которые меняют список, ничего не возвращают — результат их вызова нельзя присваивать:

python
result = cart.append("монитор")
print(result)
print(cart)

Результат:

вывод
None
['мышь', 'механическая клавиатура', 'кабель', 'монитор']

Список изменился, а result — None. Если написать cart = cart.append(...), корзина превратится в None.

Шаг 6. Отличаем срез от изменения

Срез и + создают новый список, исходный не трогают:

python
first_two = cart[:2]
first_two.append("коврик")
bigger = cart + ["коврик"]
print(cart)
print(first_two)
print(bigger)

Результат:

вывод
['мышь', 'механическая клавиатура', 'кабель', 'монитор']
['мышь', 'механическая клавиатура', 'коврик']
['мышь', 'механическая клавиатура', 'кабель', 'монитор', 'коврик']

Шаг 7. Обходим список и считаем сумму

Цены позиций — тоже список; перебираем его циклом for, как строку:

python
prices = [1499, 5990, 990]
total = 0
for price in prices:
    total += price
print(total)

Результат:

вывод
8479

Для суммы есть встроенная функция sum(prices) — она появится в теме «Встроенные функции для коллекций».

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

  • cart = cart.append(x). Методы, меняющие список, возвращают None — корзина превращается в None.
  • append вместо extend. cart.append(["коврик", "кабель"]) кладёт один элемент — вложенный список. Чтобы добавить несколько, — extend или +=.
  • remove удаляет только первое вхождение. Если товар в корзине дважды, один экземпляр останется.
  • Удаление во время обхода. for item in cart: cart.remove(item) пропускает элементы: список сдвигается под циклом. Собирайте новый список или удаляйте в цикле while.
  • Индекс за пределами. cart[10] и [].pop() — IndexError.

Итог

Список

  • Упорядоченный и изменяемый; индексы и срезы — как у строк.
  • Срез и + создают новый список, исходный не меняется.

Изменение

  • lst[i] = x — замена; append(x), insert(i, x), extend(другой) — добавление.
  • pop() / pop(i) — удалить и вернуть; remove(x) — удалить первое вхождение (нет — ValueError).
  • Методы, меняющие список, возвращают None — их результат не присваиваем.

Обход

  • for x in lst: перебирает элементы.
  • Не меняйте список, который сейчас перебираете.

Вопросы на собеседовании

Чем append отличается от extend?

append(x) добавляет x как один элемент — если x список, он окажется вложенным. extend(iterable) добавляет каждый элемент переданной коллекции по отдельности. lst += [a, b] работает как extend.

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

Это соглашение Python: методы, которые меняют объект на месте, возвращают None, чтобы было видно, что новый объект не создаётся. Отсортированную копию возвращает встроенная sorted(lst).

Что будет, если удалять элементы списка внутри for по этому же списку?

Цикл идёт по индексам: после удаления элементы сдвигаются влево, и следующий элемент «перепрыгивается». В результате часть элементов не удаляется. Правильно — построить новый список из нужных элементов.

Глубже

Почему append быстрый, а insert(0, x) и pop(0) на больших списках медленные — в курсе «Python под капотом», тема «Как устроен list».

Ошибка в тексте

Сообщить об ошибке могут зарегистрированные пользователи — так в сообщениях меньше спама.

Войти, чтобы сообщить