Встроенные функции для коллекций
Теория
У Python есть набор встроенных функций, которые работают с любой коллекцией — списком, кортежем, множеством, ключами словаря и даже строкой. Они закрывают типовые задачи, которые иначе пришлось бы писать циклом: посчитать сумму и количество, найти минимум и максимум, отсортировать, проверить «есть ли хоть один» и «все ли», пронумеровать элементы, пройти по двум спискам одновременно.
Эти функции не меняют исходную коллекцию, а возвращают результат. Отсюда главная путаница: sorted(lst) возвращает новый отсортированный список, а метод lst.sort() сортирует сам список и возвращает None. И ещё одна особенность: на пустой коллекции часть функций падает (min, max), а часть возвращает «нейтральное» значение (sum — 0, any — False, all — True).
Наглядно
Таблица 1. Встроенные функции на ценах корзины prices = [1499, 5990, 990, 490].
| Функция | Пример | Результат | На пустой коллекции |
|---|---|---|---|
len |
len(prices) |
4 |
0 |
sum |
sum(prices) |
8969 |
0 |
min, max |
min(prices), max(prices) |
490, 5990 |
ValueError; спасает default= |
sorted |
sorted(prices) |
новый список [490, 990, 1499, 5990] |
[] |
sorted(..., reverse=True) |
sorted(prices, reverse=True) |
[5990, 1499, 990, 490] |
[] |
reversed |
list(reversed(prices)) |
[490, 990, 5990, 1499] |
[] |
any |
any([p > 5000 for p in prices]) |
True — хотя бы один |
False |
all |
all([p > 0 for p in prices]) |
True — все |
True |
enumerate |
enumerate(names, start=1) |
пары (номер, элемент) |
ничего |
zip |
zip(names, prices) |
пары (название, цена) |
ничего |
Таблица 2. sorted() и метод .sort().
sorted(lst) |
lst.sort() |
|
|---|---|---|
| Что делает | возвращает новый отсортированный список | сортирует сам список |
| Возвращает | список | None |
| Исходный список | не меняется | меняется |
| С чем работает | с любой коллекцией | только со списком |
На практике
Задача: показать в корзине итоги — сумму, самую дешёвую и дорогую позиции, топ по цене, — проверить наличие и вывести пронумерованный чек.
Шаг 1. Считаем итоги
Количество позиций, сумма, минимум и максимум — каждое одной функцией:
prices = [1499, 5990, 990, 490] print(len(prices), sum(prices), min(prices), max(prices))
Результат:
4 8969 490 5990
Шаг 2. Считаем среднее
Средний чек — сумма, делённая на количество. На пустой корзине деление на ноль:
print(sum(prices) / len(prices)) empty = [] print(sum(empty) / len(empty))
Результат:
2242.25 ZeroDivisionError: division by zero
Перед делением проверяйте, что коллекция не пуста: sum(x) / len(x) if x else 0.
Шаг 3. Сортируем без изменения исходного
sorted возвращает новый список, исходный порядок цен сохраняется:
cheap_first = sorted(prices) print(cheap_first) print(prices)
Результат:
[490, 990, 1499, 5990] [1499, 5990, 990, 490]
Шаг 4. Сортируем на месте
Метод .sort() меняет сам список и возвращает None:
result = prices.sort() print(result) print(prices)
Результат:
None [490, 990, 1499, 5990]
Если исходный порядок ещё нужен (например, это порядок добавления в корзину), используйте sorted.
Шаг 5. Берём топ
Два самых дорогих товара — сортировка по убыванию и срез:
prices = [1499, 5990, 990, 490] print(sorted(prices, reverse=True)[:2])
Результат:
[5990, 1499]
Сортировка по полю словаря (например, товары по цене) требует параметра key — он появится в теме «Функции как значения и lambda».
Шаг 6. Проверяем «хоть один» и «все»
any — есть ли хотя бы одно истинное значение, all — истинны ли все. Список условий удобно собрать comprehension:
stocks = [12, 0, 40] print(any([s == 0 for s in stocks])) print(all([s > 0 for s in stocks])) print(any([]), all([]))
Результат:
True False False True
all([]) — True: на пустом наборе нет ни одного нарушения.
Шаг 7. Нумеруем через enumerate
Чек с номерами строк. enumerate выдаёт пары (номер, элемент), нумерация по умолчанию с нуля:
names = ["Мышь", "Коврик", "Кабель"] for number, name in enumerate(names, start=1): print(f"{number}. {name}")
Результат:
1. Мышь 2. Коврик 3. Кабель
Шаг 8. Идём по двум спискам через zip
Названия и цены лежат в разных списках — zip собирает пары по позициям:
prices = [1499, 490, 390] for name, price in zip(names, prices): print(f"{name}: {price} ₽") print(dict(zip(names, prices))) print(list(zip(names, [1499, 490])))
Результат:
Мышь: 1499 ₽
Коврик: 490 ₽
Кабель: 390 ₽
{'Мышь': 1499, 'Коврик': 490, 'Кабель': 390}
[('Мышь', 1499), ('Коврик', 490)]Последняя строка: если списки разной длины, zip молча останавливается на коротком — «Кабель» пропал без ошибки. С Python 3.10 можно включить проверку: zip(a, b, strict=True) выбросит ValueError.
Шаг 9. Обрабатываем пустую коллекцию
max пустого списка падает. Параметр default задаёт ответ на этот случай:
print(max([], default=0)) max([])
Результат:
0 ValueError: max() iterable argument is empty
Частые ошибки
lst = lst.sort(). Метод возвращаетNone— список теряется. Новый отсортированный список —sorted(lst).- Сортировка исходных данных.
.sort()меняет список, который может понадобиться в исходном порядке. Если сомневаетесь —sorted. min/maxпустой коллекции.ValueError; используйтеdefault=.- Деление на
lenпустой коллекции.ZeroDivisionError; проверьте, что коллекция не пуста. - Нумерация с нуля.
enumerateначинает с 0; для людей —start=1. zipразной длины. Лишние элементы теряются без ошибки; там, где длины обязаны совпадать, —strict=True.
Итог
Подсчёт
len,sum,min,max— работают с любой коллекцией.min/maxпустой коллекции —ValueError, спасаетdefault=;sum([])—0.
Сортировка
sorted(x)— новый список, исходный не меняется;reverse=True— по убыванию.lst.sort()— на месте, возвращаетNone.
Проверки
any(...)— хоть один истинный;all(...)— все истинны;any([])—False,all([])—True.
Обход
enumerate(x, start=1)— пары(номер, элемент).zip(a, b)— пары по позициям, останавливается на коротком;strict=True— проверка длины.dict(zip(keys, values))— словарь из двух списков.
Вопросы на собеседовании
Чем sorted() отличается от list.sort()?
sorted() принимает любую коллекцию и возвращает новый список, не меняя исходную. list.sort() есть только у списков, сортирует на месте и возвращает None. Обе сортировки стабильные: равные элементы сохраняют исходный порядок.
Что вернут any([]) и all([])?
False и True. any ищет хотя бы один истинный элемент — в пустом наборе его нет. all проверяет, что нет ни одного ложного, — в пустом наборе их тоже нет.
Что делает zip, если списки разной длины?
Останавливается на самом коротком, лишние элементы длинных списков отбрасываются без ошибки. С Python 3.10 zip(..., strict=True) выбрасывает ValueError при разной длине.
Глубже
Почему zip, enumerate и reversed не создают списки, а выдают элементы по одному, — в курсе «Python под капотом», раздел «Итерация и протоколы».