Зачем нужны списки
Представьте, что вы записываете оценки за контрольную у целого класса — тридцать учеников. Заводить тридцать отдельных переменных grade1, grade2, grade3 и так далее — неудобно и почти невозможно: вы не сможете написать программу, которая одинаково работает и для десяти учеников, и для тридцати. Нужен способ хранить много значений под одним именем, чтобы можно было обращаться то к одному из них, то ко всем сразу.
Именно для этого в Python существуют коллекции — типы данных, которые хранят внутри себя сразу несколько значений. Список — первая и самая ходовая из них.
Официальный термин: список (list) — это упорядоченная и изменяемая коллекция элементов. "Упорядоченная" значит, что элементы хранятся именно в том порядке, в котором вы их положили, и у каждого есть свой номер (индекс). "Изменяемая" значит, что список можно менять после создания: добавлять, удалять, заменять элементы — в отличие, например, от строки, которую после создания изменить нельзя.
Создание списка: [] и list()
Простыми словами: чтобы получить список, нужно перечислить значения через запятую и обернуть их в квадратные скобки — так же, как вы обернули бы список покупок в скобки на бумаге.
Официальный термин: запись [значение1, значение2, ...] называется литералом списка. Есть и второй способ — встроенная функция list(), которая превращает в список что-то другое: строку, диапазон range() или другую коллекцию.
grades = [5, 4, 5, 3, 5, 4]
fruits = ["яблоко", "банан", "вишня"]
empty = []
letters = list("hello")
numbers = list(range(1, 6))
| Строка | Что происходит |
|---|---|
grades = [5, 4, 5, 3, 5, 4] | Список из шести чисел через запятую в квадратных скобках. Порядок сохраняется в точности как написали. |
empty = [] | Пустые квадратные скобки — список без единого элемента. Дальше в него можно что-то добавить. |
list("hello") | list() раскладывает строку на отдельные символы: получится ["h", "e", "l", "l", "o"]. |
list(range(1, 6)) | Превращает диапазон чисел от 1 до 5 включительно в список: [1, 2, 3, 4, 5]. |
fruits[0]) и срезы (fruits[1:3]) вы уже разбирали, когда изучали индексы и срезы строк — со списками они работают ровно так же: индексация с нуля, отрицательные индексы считают с конца, срез [начало:конец] не включает элемент с индексом "конец".Добавление элементов: append, insert, extend
Простыми словами: список можно пополнять уже после создания — дописывать в конец, вставлять в середину или разом добавлять содержимое другого списка. Для каждой из этих задач в Python есть свой метод.
Термины: действие, которое можно выполнить над объектом (в данном случае — над списком), называется методом. Метод вызывают через точку после переменной: список.метод(аргументы).
cart = ["хлеб", "молоко"]
cart.append("сыр")
print(cart)
cart.insert(1, "яйца")
print(cart)
more_items = ["масло", "сахар"]
cart.extend(more_items)
print(cart)
| Вызов | Что делает | Результат |
|---|---|---|
cart.append("сыр") | Кладёт ОДИН элемент в конец списка. | ["хлеб", "молоко", "сыр"] |
cart.insert(1, "яйца") | Вставляет элемент на указанную позицию (индекс 1), остальные сдвигаются правее. | ["хлеб", "яйца", "молоко", "сыр"] |
cart.extend(more_items) | Добавляет КАЖДЫЙ элемент другого списка по отдельности, а не сам список целиком. | [..., "масло", "сахар"] |
append([5, 6]) и extend([5, 6]) — не одно и то же. append положит один элемент — сам список [5, 6], и вы получите вложенный список внутри списка. extend "распакует" его и добавит числа 5 и 6 по отдельности. Если вы хотели объединить два списка, а получили в конце вложенный список — вы перепутали append и extend.Удаление элементов: remove, pop, del, clear
Простыми словами: удалить из списка можно по-разному — зная само значение, зная его номер, или очистив список целиком. Способ выбирают в зависимости от того, что вам известно на момент удаления.
Термины: remove(значение) ищет и удаляет первое совпадение по значению. pop(индекс) удаляет элемент по индексу и, в отличие от остальных способов, возвращает удалённый элемент. del список[индекс] — это не метод, а отдельный оператор языка, тоже удаляет по индексу, но ничего не возвращает. clear() удаляет всё содержимое, оставляя пустой список.
letters = ["a", "b", "c", "b", "d"]
letters.remove("b")
print(letters)
numbers = [10, 20, 30, 40]
removed = numbers.pop(1)
print(removed)
print(numbers)
del numbers[0]
print(numbers)
Разбор по шагам:
letters.remove("b")— ищет первое"b"в списке и убирает именно его. Второе"b"остаётся:["a", "c", "b", "d"].removed = numbers.pop(1)— удаляет элемент с индексом 1 (это20) и сразу возвращает его в переменнуюremoved. Печатьremovedпокажет20.print(numbers)послеpopпокажет[10, 30, 40]— элемент с индексом 1 пропал.del numbers[0]— удаляет элемент с индексом 0 (10), но ничего не возвращает, поэтому эту строку нельзя присвоить переменной. После неёnumbersравен[30, 40].
remove(). Знаете индекс и хотите получить удалённый элемент — pop(). Знаете индекс и возвращаемое значение не нужно — del. Нужно очистить список целиком, сохранив саму переменную — clear().Поиск и подсчёт: in, index(), count(), len()
Простыми словами: иногда важно не изменить список, а просто спросить у него — есть ли там такое значение, на каком оно месте, сколько раз встречается и сколько в списке элементов вообще.
Термины: оператор in проверяет принадлежность и возвращает True или False. Метод index(значение) возвращает индекс первого совпадения. Метод count(значение) считает, сколько раз значение встречается. Функция len(список) вам уже знакома по строкам — для списка она возвращает число элементов.
nums = [3, 7, 2, 9, 7, 1]
print(7 in nums)
print(5 in nums)
print(nums.index(7))
print(nums.count(7))
print(len(nums))
По порядку: 7 in nums — True, семёрка в списке есть. 5 in nums — False, пятёрки нет. nums.index(7) вернёт 1 — это индекс ПЕРВОЙ семёрки (вторая, на индексе 4, не в счёт). nums.count(7) вернёт 2 — семёрка встречается дважды. len(nums) вернёт 6 — всего элементов.
index() не возвращает -1 и не молчит — он останавливает программу ошибкой ValueError. Перед вызовом index() для значения, в котором вы не уверены, сначала проверяйте его через in:if 100 in nums:
position = nums.index(100)Сортировка: sort() и sorted()
Простыми словами: список чисел или строк можно расставить по возрастанию или убыванию. Разница между двумя способами — в том, что происходит с исходным списком.
Термины: sort() — метод, который сортирует список "на месте": меняет сам исходный список и ничего не возвращает (точнее, возвращает None). sorted(список) — встроенная функция, которая создаёт и возвращает НОВЫЙ отсортированный список, а исходный оставляет без изменений.
nums = [3, 1, 4, 1, 5]
nums.sort()
print(nums)
original = [3, 1, 4, 1, 5]
new_list = sorted(original)
print(original)
print(new_list)
desc = sorted(original, reverse=True)
print(desc)
Что произошло: nums.sort() отсортировал сам список nums — печать покажет [1, 1, 3, 4, 5]. А вот original после sorted(original) остался прежним: [3, 1, 4, 1, 5], потому что sorted() не трогает исходный список, а собирает новый и отдаёт его в new_list. Аргумент reverse=True у обоих способов разворачивает порядок на убывание.
sort(). Нужно сохранить оригинал и получить отдельный отсортированный список — берите sorted().Копирование: почему b = a — ловушка
Простыми словами: когда вы пишете b = a для чисел или строк, у вас появляются два независимых значения. Со списками это правило неожиданно ломается — и это самая частая путаница у новичков.
Термин: список — изменяемый объект, и переменная хранит не сам список, а ссылку на него — место, где он лежит в памяти. Запись b = a не создаёт новый список, а создаёт второе имя для ТОГО ЖЕ списка. Изменение через одно имя видно через другое.
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)
c = a.copy()
c.append(99)
print(a)
print(c)
Разбор: b = a — теперь a и b смотрят на один и тот же список. b.append(4) меняет этот единственный список, поэтому и print(a), и print(b) покажут [1, 2, 3, 4], хотя изменяли через b. Дальше c = a.copy() создаёт настоящую, независимую копию. c.append(99) меняет только c: print(a) по-прежнему покажет [1, 2, 3, 4], а print(c) — [1, 2, 3, 4, 99].
b = a.copy() или срез b = a[:] — оба варианта создают новый список с теми же элементами, но никак не связанный с исходным.Объединение и повтор: + и *
Простыми словами: два списка можно "склеить" в один новый, а один список — размножить несколько раз подряд.
Термин: оператор + между списками возвращает НОВЫЙ список из элементов обоих, не трогая исходные. Оператор * между списком и числом повторяет содержимое списка нужное число раз.
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(c)
print(a)
zeros = [0] * 5
print(zeros)
c = a + b создаёт новый список [1, 2, 3, 4, 5, 6], а a остаётся [1, 2, 3] — операция ничего не меняет в исходных списках. [0] * 5 повторяет список из одного нуля пять раз подряд: [0, 0, 0, 0, 0]. Этим приёмом удобно готовить заготовку нужного размера, например поле для игры.
Перебор списка через while
Простыми словами: часто нужно "пройтись" по всем элементам списка одному за другим — например, чтобы напечатать каждый. Вы уже умеете это делать циклом while, используя индекс как счётчик.
fruits = ["яблоко", "банан", "вишня"]
i = 0
while i < len(fruits):
print(fruits[i])
i += 1
Разбор: i = 0 — начинаем с первого индекса. Условие i < len(fruits) держит цикл, пока индекс не выйдет за границы списка. fruits[i] внутри тела берёт элемент под текущим номером. i += 1 в конце каждого прохода сдвигает счётчик на следующий индекс. Программа напечатает по очереди яблоко, банан, вишня.
Вложенные списки — матрицы и таблицы
Простыми словами: список может хранить внутри себя другие списки. Так получают таблицы — например, шахматную доску или таблицу оценок, где есть и строки, и столбцы.
Термин: список, элементами которого являются другие списки, называют вложенным списком, а прямоугольную таблицу из чисел — матрицей. Чтобы попасть в конкретную ячейку, к списку применяют индекс дважды подряд: matrix[строка][столбец].
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
print(matrix[0][0])
print(matrix[1][2])
matrix[0][1] = 99
print(matrix[0])
Разбор: matrix — это список из трёх списков, каждый по три числа. matrix[0] берёт первую строку целиком, [1, 2, 3], а второй индекс [0] берёт из неё первый элемент — получаем 1. matrix[1][2] означает "вторая строка (индекс 1), третий элемент (индекс 2)" — это 6. Присваивание matrix[0][1] = 99 заменяет элемент внутри вложенного списка: строка с индексом 0 становится [1, 99, 3].
Частые ошибки
Ошибка 1. Спутать append и extend.
items = [1, 2, 3]
items.append([4, 5])
print(items)
Ожидали [1, 2, 3, 4, 5], а получили [1, 2, 3, [4, 5]] — список [4, 5] добавился как один-единственный элемент. Нужен был extend([4, 5]).
Ошибка 2. Забыть, что index() падает с ошибкой.
colors = ["красный", "синий"]
position = colors.index("зелёный")
Программа остановится с ValueError: 'зелёный' is not in list, потому что такого значения в списке нет. Перед вызовом index() для непроверенного значения используйте in.
Ошибка 3. Думать, что b = a создаёт копию.
original = [1, 2, 3]
backup = original
backup.append(4)
print(original)
Многие ждут, что original не изменится, ведь меняли backup. На деле выведет [1, 2, 3, 4] — backup и original это одно и то же место в памяти под двумя именами. Для независимой копии нужен original.copy().
Что важно запомнить
[] или list().append добавляет один элемент в конец, insert — на конкретную позицию, extend — сразу все элементы другого списка.remove(значение) удаляет по значению, pop(индекс) удаляет по индексу и возвращает элемент, del список[индекс] удаляет без возврата, clear() очищает список полностью.in проверяет наличие значения, index() находит его позицию (и падает с ошибкой, если значения нет), count() считает повторы, len() — общее число элементов.sort() сортирует список на месте и возвращает None; sorted() возвращает новый список, а исходный не трогает.b = a НЕ копирует список — создаёт второе имя для того же списка. Для копии нужен a.copy() или a[:].matrix[строка][столбец].Проверьте себя
5 вопросов
Корзина покупок
Дана корзина покупок cart и каталог магазина: список товаров catalog_items и список цен catalog_prices (цена товара catalog_items[i] находится в catalog_prices[i], то есть у товаров и цен одинаковые индексы). Выполните по порядку четыре действия:
- добавьте в конец
cartтовар"сыр"(методappend); - вставьте товар
"яйца"на позицию с индексом 1 (методinsert); - удалите из корзины первое вхождение товара
"хлеб"(методremove); - посчитайте итоговую стоимость товаров, оставшихся в корзине, в переменную
total— для каждого товара изcartнайдите его позицию вcatalog_itemsчерез.index()и возьмите цену с той же позицией вcatalog_prices.
После каждого шага заготовка уже сохраняет копию корзины в отдельную переменную — эти строки менять не нужно.