Списки
Теория
Список (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. Создаём список и читаем элементы
Корзина — список названий товаров:
cart = ["мышь", "клавиатура"] print(cart[0], cart[-1], len(cart)) print("мышь" in cart, "монитор" in cart)
Результат:
мышь клавиатура 2 True False
Шаг 2. Заменяем элемент
Покупатель выбрал механическую клавиатуру вместо обычной — меняем элемент по индексу:
cart[1] = "механическая клавиатура" print(cart)
Результат:
['мышь', 'механическая клавиатура']
Со строкой так нельзя (TypeError), со списком — можно: он изменяемый.
Шаг 3. Добавляем товары
append добавляет один элемент в конец, insert — по индексу, extend — все элементы другого списка:
cart.append("коврик") cart.insert(0, "наушники") cart.extend(["кабель", "подставка"]) print(cart)
Результат:
['наушники', 'мышь', 'механическая клавиатура', 'коврик', 'кабель', 'подставка']
Шаг 4. Убираем товары
pop удаляет по индексу и возвращает удалённое, remove — по значению:
last = cart.pop() first = cart.pop(0) cart.remove("коврик") print(last, first) print(cart)
Результат:
подставка наушники ['мышь', 'механическая клавиатура', 'кабель']
Если значения в списке нет, remove падает:
cart.remove("монитор")Результат:
ValueError: list.remove(x): x not in list
Шаг 5. Помним, что методы возвращают None
Методы, которые меняют список, ничего не возвращают — результат их вызова нельзя присваивать:
result = cart.append("монитор") print(result) print(cart)
Результат:
None ['мышь', 'механическая клавиатура', 'кабель', 'монитор']
Список изменился, а result — None. Если написать cart = cart.append(...), корзина превратится в None.
Шаг 6. Отличаем срез от изменения
Срез и + создают новый список, исходный не трогают:
first_two = cart[:2] first_two.append("коврик") bigger = cart + ["коврик"] print(cart) print(first_two) print(bigger)
Результат:
['мышь', 'механическая клавиатура', 'кабель', 'монитор'] ['мышь', 'механическая клавиатура', 'коврик'] ['мышь', 'механическая клавиатура', 'кабель', 'монитор', 'коврик']
Шаг 7. Обходим список и считаем сумму
Цены позиций — тоже список; перебираем его циклом for, как строку:
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».