Справочник по Python · модуль 3 · списки и циклы
Глава 3.11
Методы списков:
удаление, поиск, сортировка
pop() извлекает элемент, clear() очищает список, index() и count() исследуют содержимое, а sort() меняет порядок элементов.
- Категория
- Методы list
- Уровень
- Начальный
- Связанные темы
- Индексы, удаление, сравнение
- Зачем это знать
- Извлекать, искать, считать и сортировать элементы
§1pop(): удалить и вернуть
pop() отличается от всех методов предыдущей главы тем, что возвращает значение, а не None. Он удаляет элемент и отдаёт его программе.
numbers = [10, 20, 30] removed = numbers.pop() print(numbers) print(removed)
[10, 20] 30
Без аргумента удаляется последний элемент. Именно поэтому removed = numbers.pop() — правильная запись, в отличие от numbers = numbers.append(...) из главы 3.10.
Если извлечённое значение не нужно, результат можно не сохранять: numbers.pop() отдельной строкой просто удалит последний элемент.
§2pop() по индексу
pop(index) удаляет элемент с указанной позиции. Элементы правее сдвигаются влево, и их индексы уменьшаются на единицу.
numbers = [10, 20, 30] removed = numbers.pop(1) print(removed) print(numbers)
20 [10, 30]
было: 10(0) 20(1) 30(2) стало: 10(0) 30(1)
Отрицательный индекс поддерживается: pop(-1) извлекает последний элемент. Если списка нет элемента с таким индексом — в том числе если список пуст, — возникает IndexError.
§3Список как стек
Пара append() и pop() превращает список в стек: последний добавленный элемент выходит первым. Такой порядок называют LIFO — last in, first out.
stack = [] stack.append(1) stack.append(2) stack.append(3) print(stack.pop()) print(stack)
3 [1, 2]
Так устроены отмена последнего действия, история переходов «назад» и разбор вложенных скобок: везде, где нужно вернуться к тому, что отложили последним.
§4Список как очередь
pop(0) извлекает первый элемент — получается очередь, где первым выходит тот, кто раньше пришёл (FIFO).
queue = ["Анна", "Борис", "Вера"] first = queue.pop(0) print(first) print(queue)
Анна ['Борис', 'Вера']
Работает это корректно, но не бесплатно: после удаления нулевого элемента все остальные сдвигаются на одну позицию. Для списка из миллиона элементов каждый pop(0) — миллион перемещений, тогда как pop() с конца обходится без них.
Для больших очередей в стандартной библиотеке есть collections.deque с методом popleft(): он удаляет первый элемент без сдвига остальных. В учебных задачах на десятки элементов разница незаметна, и pop(0) вполне уместен.
§5clear(): очистить список
clear() удаляет все элементы, сохраняя сам список.
numbers = [1, 2, 3, 4] numbers.clear() print(numbers) print(len(numbers))
[] 0
§6clear() или новый список
На первый взгляд numbers.clear() и numbers = [] делают одно и то же. Разница проявляется, когда у списка два имени — как в главе 3.10.
numbers = [1, 2, 3] another = numbers numbers.clear() print(numbers) print(another)
[] []
numbers = [1, 2, 3] another = numbers numbers = [] print(numbers) print(another)
[] [1, 2, 3]
clear() опустошает сам объект — его видят все имена. Присваивание numbers = [] создаёт новый пустой список и связывает с ним только имя numbers; прежний список продолжает жить под именем another.
Нужно, чтобы изменение увидели все, кто работает с этим списком, — clear(). Нужно просто начать накопление заново в своей переменной — = [].
§7index(): найти позицию
index(value) возвращает индекс первого вхождения значения.
numbers = [10, 20, 30, 20] print(numbers.index(20)) print(numbers.index(20, 2))
1 3
Второй аргумент задаёт позицию, с которой начинать поиск. Полная форма — index(value, start, stop); правая граница stop не включается, как и в range().
Если значения нет, возникает ValueError. Поэтому index() обычно ставят после проверки:
numbers = [10, 20, 30] value = 99 if value in numbers: print(numbers.index(value)) else: print("значение не найдено")
значение не найдено
§8Все позиции значения
index() находит только первое вхождение. Если нужны все, список перебирают по индексам и собирают подходящие позиции.
numbers = [10, 20, 30, 20] positions = [] for index in range(len(numbers)): if numbers[index] == 20: positions.append(index) print(positions)
[1, 3]
Здесь соединяются приёмы двух глав: перебор по индексам из 3.5 и накопление через append() из 3.2. Такая пара решает большинство задач «найти все, что подходит под условие».
§9count(): посчитать совпадения
count(value) проходит список и возвращает число равных элементов. Если совпадений нет, результатом будет 0, а не ошибка.
numbers = [1, 2, 2, 3, 2] print(numbers.count(2)) print(numbers.count(9))
3 0
| Нужно узнать | Запись | Если значения нет |
|---|---|---|
| есть ли значение | value in items | False |
| сколько раз встречается | items.count(value) | 0 |
| на какой позиции | items.index(value) | ValueError |
Из трёх способов проверки только index() может остановить программу — это и делает его самым опасным.
§10sort(): сортировать на месте
sort() меняет порядок элементов исходного списка и возвращает None. По умолчанию числа идут по возрастанию.
numbers = [5, 2, 9, 1] numbers.sort() print(numbers) numbers.sort(reverse=True) print(numbers)
[1, 2, 5, 9] [9, 5, 2, 1]
Аргумент reverse=True задаёт убывание. Python использует устойчивый алгоритм Timsort со сложностью порядка O(n log n) для общего случая: «устойчивый» означает, что равные элементы сохраняют исходный взаимный порядок.
§11Сортировка строк и ключ
Строки сортируются по алфавиту — точнее, по кодам символов.
names = ["Вера", "Анна", "Борис"] names.sort() print(names)
['Анна', 'Борис', 'Вера']
Аргумент key — тема главы 6.10, но одну его форму удобно знать сразу. Он задаёт, по какому признаку сравнивать элементы. Например, по длине строки:
words = ["дом", "а", "книга"] words.sort(key=len) print(words)
['а', 'дом', 'книга']
Обратите внимание: у len нет скобок. Передаётся сама функция, а вызывать её для каждого элемента будет уже sort().
Сравниваются коды символов, а не буквы «по-человечески». Поэтому "Яблоко" окажется раньше "арбуз". Чтобы регистр не влиял, используют names.sort(key=str.lower).
Смешивать несравнимые типы нельзя: [1, "a"].sort() вызовет TypeError — Python не знает, что больше, число или строка.
§12sort() или sorted()
| Запись | Исходный список | Результат |
|---|---|---|
numbers.sort() | изменяется | None |
sorted(numbers) | не изменяется | новый отсортированный список |
numbers = [3, 1, 2] ordered = sorted(numbers) print(numbers) print(ordered)
[3, 1, 2] [1, 2, 3]
Разница та же, что между reverse() и [::-1] или между clear() и = []: метод меняет объект, функция строит новый. sorted() к тому же принимает любую коллекцию — строку, кортеж, множество — и всегда возвращает список.
§13Удаление внутри цикла
Есть ошибка, которую совершают почти все и которая не выдаёт никакого сообщения. Задача: убрать из списка все двойки.
numbers = [1, 2, 2, 3, 2] for number in numbers: if number == 2: numbers.remove(number) print(numbers)
[1, 3, 2]
Причина в том, что цикл идёт по позициям, а удаление сдвигает элементы влево. Внутренний счётчик цикла об этом не знает и продолжает увеличиваться, перепрыгивая через элементы.
| Позиция цикла | Список сейчас | Взят элемент | Действие |
|---|---|---|---|
0 | [1, 2, 2, 3, 2] | 1 | пропуск |
1 | [1, 2, 2, 3, 2] | 2 | удалена, список стал [1, 2, 3, 2] |
2 | [1, 2, 3, 2] | 3 | вторая двойка пропущена: она сдвинулась на позицию 1 |
3 | [1, 2, 3, 2] | 2 | удалена первая двойка, список стал [1, 3, 2] |
4 | [1, 3, 2] | — | элементов больше нет, цикл заканчивается |
Надёжное решение — не удалять из того, что перебираешь, а собрать новый список из подходящих элементов.
numbers = [1, 2, 2, 3, 2] kept = [] for number in numbers: if number != 2: kept.append(number) print(kept)
[1, 3]
Второй вариант — перебирать копию, а удалять из оригинала: for number in numbers.copy(). Тогда цикл идёт по неизменяемому набору, и сдвиги ему не мешают.
Не изменяйте длину списка, пока перебираете его циклом. Ошибки при этом не будет — будет тихо неверный результат.
§14Способы удаления
| Запись | Что выбирает | Возвращает удалённое | Если не найдено |
|---|---|---|---|
pop(index) | индекс, по умолчанию последний | да | IndexError |
remove(value) | первое равное значение | нет | ValueError |
del items[index] | индекс или срез | нет | IndexError |
clear() | все элементы | нет | — |
Выбор простой: знаете позицию — pop() или del; знаете значение — remove(); нужно значение обратно — только pop().
§15Частые ошибки
| Что написано | Что произойдёт | Как правильно |
|---|---|---|
items = items.sort() | в items попадёт None | items.sort() |
| удалять элементы в цикле по тому же списку | часть элементов будет пропущена, ошибки не будет | собрать новый список или перебирать items.copy() |
[].pop() | IndexError | проверить, что список не пуст |
items.index(value) без проверки | ValueError, если значения нет | сначала проверить value in items |
ожидать все позиции от index() | вернётся только первая | использовать цикл для всех совпадений |
items.sort(key=len()) | TypeError: функция вызвана вместо передачи | items.sort(key=len) |
| сортировать вместе числа и строки | TypeError: их нельзя сравнить | сравнивать совместимые значения |
numbers = [] для очистки общего списка | другие имена продолжат видеть старое содержимое | numbers.clear() |
§16Проверьте себя
Чем pop() отличается от remove()?
pop() удаляет по индексу и возвращает элемент, а remove() удаляет первое совпавшее значение и возвращает None.
Почему pop(0) медленнее, чем pop()?
После удаления первого элемента все остальные сдвигаются на одну позицию, а удаление с конца сдвигов не требует.
Чем clear() отличается от numbers = []?
clear() опустошает сам объект, и это видят все его имена. Присваивание создаёт новый пустой список только для одной переменной.
Что вернёт count(), если совпадений нет?
Число 0. В отличие от index(), ошибки не будет.
Почему нельзя удалять элементы прямо в цикле по этому же списку?
Удаление сдвигает элементы влево, а счётчик цикла продолжает расти — часть элементов оказывается пропущена.
Как отсортировать, не меняя исходный список?
Сохранить результат sorted(numbers) в новую переменную.
§17Шпаргалка
value = items.pop(index)items.pop()items.pop(0)items.clear()items.index(x)items.count(x)items.sort(reverse=True)items.sort(key=len)ordered = sorted(items)Итог главы
pop() удаляет и возвращает элемент, clear() очищает список, index() находит первую позицию, count() считает совпадения, а sort() сортирует исходный список. Для нового отсортированного списка используют sorted(). И главное правило безопасности: не менять длину списка, пока идёт цикл по нему.