list: создание, доступ, добавление, удаление, поиск и перебор

Цели урока
  • Создавать список и обращаться к элементам по положительному и отрицательному индексу
  • Добавлять и удалять элементы с помощью append, insert, remove, pop и del
  • Искать в списке с помощью in, index и count
  • Перебирать список, в том числе с enumerate, и сортировать его

Что мы изучим?

list (список) — самая распространённая структура данных в Python. Мы уже коротко им пользовались. Сегодня изучим его как следует:

  • Создание и доступ к элементам.
  • Добавление, удаление и изменение.
  • Поиск.
  • Перебор и сортировку.

Зачем это нужно?

Почти каждая программа хранит коллекции: список студентов, товары в корзине, сегодняшние заказы, строки из файла, результаты запроса к базе данных (темы бэкенда и баз данных). Когда количество заранее неизвестно, нельзя завести отдельную переменную для каждого элемента (student1, student2…). Список хранит столько, сколько нужно, в определённом порядке.

Объяснение с основ

Что такое список?

Список (list) — упорядоченная коллекция значений:

  • Упорядоченная — у каждого элемента есть фиксированная позиция, индекс.
  • Изменяемая (mutable) — после создания можно добавлять, удалять и менять элементы.
  • Допускает повторы — одно и то же значение может встречаться несколько раз.
  • Любой тип — можно смешивать ([1, "a", True]), но обычно список хранит однородные элементы.
Аналогия: поезд

Список — поезд с пронумерованными вагонами. Каждый вагон (элемент) везёт груз (значение). Первый вагон — номер 0, а не 1. Можно прицепить вагон в конце (append), поставить вагон в середину (insert) или отцепить вагон (remove/pop).

Индексы

fruits = ["apple", "banana", "cherry", "date"]
index:       0         1         2        3
negative:   -4        -3        -2       -1
  • Отсчёт начинается с 0.
  • Отрицательный индекс считает с конца: -1 = последний, -2 = предпоследний.
  • Несуществующий индекс → IndexError.

Синтаксис

# create
empty = []
numbers = [10, 20, 30]

# access and change
numbers[0]          # 10 - first item
numbers[-1]         # 30 - last item
numbers[1] = 25     # change an item
len(numbers)        # 3 - how many items

# add
numbers.append(40)       # add to the end
numbers.insert(0, 5)     # insert at index 0, pushing the rest right

# remove
numbers.remove(25)       # remove the FIRST item equal to 25
last = numbers.pop()     # remove and return the last item
first = numbers.pop(0)   # remove and return the item at index 0
del numbers[0]           # delete by index (returns nothing)
numbers.clear()          # remove everything

# search
30 in numbers            # True / False
numbers.index(30)        # index of the first 30 (ValueError if missing)
numbers.count(30)        # how many times 30 appears

# sort
numbers.sort()               # sorts THIS list in place
numbers.sort(reverse=True)   # descending
sorted(numbers)              # returns a NEW sorted list, original unchanged

Метод — функция, которая «принадлежит» объекту и вызывается через точку: numbers.append(40). Подробно о методах — в теме ООП. Пока: «действие, которое список умеет делать сам над собой».

Первый пример кода

week-2/shopping_list.py:

shopping = ["milk", "bread", "eggs"]
print("Start:", shopping)

shopping.append("cheese")
print("After append:", shopping)

shopping.insert(1, "butter")
print("After insert:", shopping)

shopping.remove("bread")
print("After remove:", shopping)

print("First item:", shopping[0])
print("Last item:", shopping[-1])
print("Items count:", len(shopping))

Вывод:

Start: ['milk', 'bread', 'eggs']
After append: ['milk', 'bread', 'eggs', 'cheese']
After insert: ['milk', 'butter', 'bread', 'eggs', 'cheese']
After remove: ['milk', 'butter', 'eggs', 'cheese']
First item: milk
Last item: cheese
Items count: 4

Разбор кода построчно

СтрокаЧто произошло со списком
shopping = [...]Создан с 3 элементами: индексы 0, 1, 2.
.append("cheese")Добавлен в конец. Теперь 4 элемента.
.insert(1, "butter")Вставлен на индекс 1. То, что там было (bread), и всё после него сдвинулось вправо.
.remove("bread")Удалён по значению: Python ищет первое вхождение "bread" и удаляет его.
shopping[0]Первый элемент.
shopping[-1]Последний элемент — без знания, сколько их.
len(shopping)Количество элементов.

Обратите внимание: append, insert и remove меняют сам список и не возвращают новый список. Поэтому не пишут shopping = shopping.append(...) (подробнее — в разделе ошибок).

Ещё один пример

Управление очередью на кассе: перебор, поиск, pop и enumerate. week-2/queue.py:

queue = ["dana", "avi", "noa", "avi", "yossi"]

print("People in queue:", len(queue))
print("Is noa waiting?", "noa" in queue)
print("noa's position:", queue.index("noa") + 1)
print("How many times avi:", queue.count("avi"))

served = queue.pop(0)
print("Now serving:", served)

print("--- Remaining queue ---")
for position, name in enumerate(queue, start=1):
    print(position, name)

queue.sort()
print("Alphabetical:", queue)

Вывод:

People in queue: 5
Is noa waiting? True
noa's position: 3
How many times avi: 2
Now serving: dana
--- Remaining queue ---
1 avi
2 noa
3 avi
4 yossi
Alphabetical: ['avi', 'avi', 'noa', 'yossi']

Разбор:

  • "noa" in queue — in проходит по списку и проверяет, есть ли значение. Возвращает bool.
  • queue.index("noa") + 1 — index возвращает индекс (2). Добавляем 1, потому что для людей «третье место» считается с 1.
  • queue.pop(0) — извлекает и возвращает первого. В этом отличие от remove: pop отдаёт извлечённое значение, и им можно воспользоваться (served).
  • enumerate(queue, start=1) — на каждом круге даёт пару: порядковый номер и элемент. for position, name in ... распаковывает пару в две переменные. Без start=1 счёт начинается с 0.
  • queue.sort() — сортирует сам список: текст — по алфавиту, числа — по возрастанию.

Типичная ошибка

Ошибка 1: присвоить результат метода, который меняет список на месте.

names = ["noa", "avi"]
names = names.append("dana")
print(names)
None

append меняет список и возвращает None. Мы присвоили None в names и потеряли список! Исправление: просто names.append("dana"). То же самое для sort(), insert(), remove().

Ошибка 2: ошибка на единицу (off-by-one) на последнем индексе.

items = ["a", "b", "c"]
print(items[len(items)])
IndexError: list index out of range

len равно 3, но последний индекс — 2. Последний = items[-1] или items[len(items) - 1].

Ошибка 3: remove для несуществующего значения.

items.remove("z")
ValueError: list.remove(x): x not in list

Сначала проверьте: if "z" in items: items.remove("z").

Ошибка 4: удалять из списка во время его перебора.

numbers = [1, 2, 2, 3]
for n in numbers:
    if n == 2:
        numbers.remove(n)
print(numbers)
[1, 2, 3]

Мы ожидали [1, 3]. Когда удаляется элемент, все элементы сдвигаются влево, и цикл «перепрыгивает» следующий элемент. Безопасное решение: построить новый список из того, что нужно оставить:

numbers = [1, 2, 2, 3]
kept = []
for n in numbers:
    if n != 2:
        kept.append(n)
print(kept)   # [1, 3]

Практика

Упражнения опираются только на то, что пройдено в этом уроке и в предыдущих. Сначала попробуйте сами, и только потом открывайте решение.

Упражнение 1: Индексы

days = ["Sun", "Mon", "Tue", "Wed", "Thu"]

Напечатайте, используя только индексы: первый день, последний день (с отрицательным индексом) и средний день.

Ожидаемый вывод:

Sun
Thu
Tue
Показать решение
days = ["Sun", "Mon", "Tue", "Wed", "Thu"]

print(days[0])
print(days[-1])
print(days[2])
Sun
Thu
Tue

Индексы начинаются с 0. Отрицательный индекс считает с конца: -1 — последний элемент.

Упражнение 2: Список покупок

Начните с ["milk", "bread"] и выполните по порядку:

  1. Добавьте "eggs" в конец.
  2. Добавьте "butter" на первое место.
  3. Удалите "bread".
  4. Напечатайте список и количество элементов.

Ожидаемый вывод:

['butter', 'milk', 'eggs']
3
Показать решение
shopping = ["milk", "bread"]

shopping.append("eggs")
shopping.insert(0, "butter")
shopping.remove("bread")

print(shopping)
print(len(shopping))
['butter', 'milk', 'eggs']
3
  • append — в конец. insert(0, ...) — на определённую позицию.
  • remove — удаляет по значению (первое вхождение).

Упражнение 3: Очередь

queue = ["dana", "avi", "noa", "avi", "yossi"]
  1. Проверьте, есть ли "noa" в очереди, и напечатайте, на каком она месте (первое место — 1).
  2. Напечатайте, сколько раз встречается "avi".
  3. Выведите из очереди первого человека и напечатайте Now serving: <name>, а также количество оставшихся.

Ожидаемый вывод:

True
3
2
Now serving: dana
4
Показать решение
queue = ["dana", "avi", "noa", "avi", "yossi"]

print("noa" in queue)
print(queue.index("noa") + 1)
print(queue.count("avi"))

served = queue.pop(0)
print("Now serving:", served)
print(len(queue))
True
3
2
Now serving: dana
4

pop(0) и удаляет, и возвращает элемент — поэтому его можно сохранить в переменной.

Упражнение 4: Статистика по оценкам

grades = [78, 92, 55, 88, 100, 43, 67]

Напечатайте самую высокую оценку, самую низкую, среднее (округлённое до одного знака) и новый список сдавших оценок (55 и выше) — не меняя grades.

Ожидаемый вывод:

Highest: 100
Lowest: 43
Average: 74.7
Passed: [78, 92, 55, 88, 100, 67]
Показать решение
PASSING_GRADE = 55

grades = [78, 92, 55, 88, 100, 43, 67]

print("Highest:", max(grades))
print("Lowest:", min(grades))
print("Average:", round(sum(grades) / len(grades), 1))

passed = []
for grade in grades:
    if grade >= PASSING_GRADE:
        passed.append(grade)
print("Passed:", passed)
Highest: 100
Lowest: 43
Average: 74.7
Passed: [78, 92, 55, 88, 100, 67]

Шаблон «новый список + цикл + append» — способ отфильтровать список, не трогая оригинал.

Упражнение 5: Удаление во время цикла

numbers = [1, 2, 2, 3, 2, 4]
for n in numbers:
    if n == 2:
        numbers.remove(n)
print(numbers)

Задумано было удалить все двойки, но одна осталась. Напишите функцию remove_all(items, value), которая возвращает новый список без единого вхождения value.

Ожидаемый вывод:

[1, 3, 4]
Показать решение

Когда вы удаляете из списка во время его перебора, элементы сдвигаются влево, и цикл пропускает элемент, который переместился на место удалённого. Поэтому вместо этого строят новый список:

def remove_all(items, value):
    result = []
    for item in items:
        if item != value:
            result.append(item)
    return result


print(remove_all([1, 2, 2, 3, 2, 4], 2))
[1, 3, 4]

Итоги

  • list = упорядоченная изменяемая коллекция с повторами. Записывается через [ ].
  • Индекс начинается с 0. -1 = последний. Несуществующий индекс → IndexError.
  • Добавление: append (в конец), insert (на позицию). Удаление: remove (по значению), pop (по позиции, возвращает элемент), del.
  • Поиск: in, index, count. Перебор: for, а enumerate — когда нужен ещё и номер.
  • Методы, которые меняют на месте (append, sort…), возвращают None. sorted() возвращает новый список.
  • Не удаляйте из списка во время его перебора. Стройте новый список.

Официальная документация