Сортировка в Python: понятное руководство по sorted, list.sort, key и многокритериальной сортировке
Запрос: «сортировка в Python sorted sort key reverse»
Сортировка — базовый навык, который встречается в задачах от парсинга до веб‑разработки и анализа данных. Python предлагает мощные, но простые инструменты: встроенную функцию sorted() и метод списка list.sort(). Разберём разницу, параметр key, флаг reverse, многокритериальную сортировку и частые ошибки.
sorted vs list.sort: в чём разница
- sorted(iterable, *, key=None, reverse=False) — возвращает новый отсортированный список, не меняя исходные данные.
- list.sort(*, key=None, reverse=False) — сортирует список на месте и возвращает None.
nums = [3, 1, 2]
print(sorted(nums)) # [1, 2, 3]
print(nums) # [3, 1, 2] — исходный список не изменился
nums.sort()
print(nums) # [1, 2, 3] — отсортирован на месте
Выбирайте sorted, если нужно сохранить исходную коллекцию, и sort, если важна экономия памяти и скорость при работе именно со списком.
Параметр key: сортируем по «ключу»
Параметр key — это функция, которая для каждого элемента возвращает значение, по которому и будет происходить сравнение. Это быстрее и надёжнее, чем «ручное» сравнение внутри компараторов.
words = ["Banana", "apple", "cherry"]
# Регистр-независимая сортировка
print(sorted(words, key=str.lower)) # ['apple', 'Banana', 'cherry']
people = [
{"name": "Ann", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Carl", "age": 25},
]
# Сортируем список словарей по возрасту
print(sorted(people, key=lambda p: p["age"]))
reverse=True: сортировка по убыванию
scores = [10, 70, 30]
print(sorted(scores, reverse=True)) # [70, 30, 10]
Важно: reverse=True инвертирует порядок уже после вычисления ключей. Это корректный способ сортировать по убыванию. Не меняйте знак ключа для строк, дат и т. п. — это либо не сработает, либо усложнит код.
Многокритериальная сортировка: кортежи в key
Python поддерживает сравнение кортежей поэлементно, поэтому удобно возвращать из key несколько полей сразу.
# Сортировка: возраст по возрастанию, затем имя по алфавиту
print(sorted(people, key=lambda p: (p["age"], p["name"])) )
# Числа сначала (None в конец), потом по алфавиту
items = ["b", None, "a", "10"]
print(sorted(items, key=lambda x: (x is None, str(x))))
Сортировка в Python стабильная: элементы с одинаковым ключом сохраняют исходный порядок. Это позволяет сортировать «по шагам»: сначала по вторичному критерию, затем по первичному — итог будет эквивалентен кортежам в key.
# Эквивалент многокритериальной сортировке
people2 = people[:]
people2.sort(key=lambda p: p["name"]) # 2-й критерий
people2.sort(key=lambda p: p["age"]) # 1-й критерий (главный)
Сортировка словарей и списков словарей
Словари как структура неупорядоченно-упорядоченные по вставке, но сортировать обычно нужно представление: пары items или ключи.
d = {"c": 3, "a": 1, "b": 2}
# По ключу
print(sorted(d.items(), key=lambda kv: kv[0])) # [('a', 1), ('b', 2), ('c', 3)]
# По значению
print(sorted(d.items(), key=lambda kv: kv[1])) # [('a', 1), ('b', 2), ('c', 3)]
# Список словарей: безопасно с отсутствующими полями
people3 = [
{"name": "Ann", "age": 30},
{"name": "Bob"}, # age отсутствует
{"name": "Carl", "age": 25},
]
print(sorted(people3, key=lambda p: (p.get("age") is None, p.get("age", 0))))
Быстрые помощники: operator.itemgetter и attrgetter
Они чуть быстрее и короче лямбд.
from operator import itemgetter, attrgetter
# Для словарей
print(sorted(people, key=itemgetter("age", "name")))
# Для объектов
class User:
def __init__(self, name, score):
self.name = name
self.score = score
users = [User("Ann", 70), User("Bob", 70), User("Carl", 90)]
print([u.name for u in sorted(users, key=attrgetter("score", "name"))])
Сортировка по датам и числам внутри строк
По дате
from datetime import datetime
rows = [
{"dt": "2025-03-01"},
{"dt": "2024-11-12"},
{"dt": "2025-01-10"},
]
print(sorted(rows, key=lambda r: datetime.fromisoformat(r["dt"])))
Если разбор даты дорогой, применяйте «украшать–сортировать–разукрашивать» (DSU): предварительно посчитать ключи и переиспользовать их.
pairs = [ (datetime.fromisoformat(r["dt"]), r) for r in rows ]
pairs.sort(key=lambda p: p[0])
rows_sorted = [ r for _, r in pairs ]
«Естественная» сортировка: file2 перед file10
import re
def natural_key(s: str):
return [int(part) if part.isdigit() else part.lower()
for part in re.split(r"(\d+)", s)]
files = ["file2.txt", "file10.txt", "file1.txt"]
print(sorted(files, key=natural_key)) # ['file1.txt', 'file2.txt', 'file10.txt']
Когда нужен компаратор: functools.cmp_to_key
Иногда проще описать «как сравнивать два элемента», а не «какой у них ключ». Тогда используйте cmp_to_key для совместимости с key-сортировкой.
from functools import cmp_to_key
def last_digit_cmp(a, b):
return (a % 10) - (b % 10)
nums = [21, 32, 14, 45]
print(sorted(nums, key=cmp_to_key(last_digit_cmp))) # [21, 32, 14, 45]
Но помните: key-основанная сортировка в Python быстрее и проще. Компараторы используйте только при реальной необходимости.
Производительность и лучшие практики
- Сортировки в CPython — Timsort: O(n log n), стабильная, хорошо работает на частично отсортированных данных.
- Предпочитайте key вместо компараторов — это быстрее и чище.
- Дорогие ключи кэшируйте (DSU), чтобы не вычислять их многократно.
- Нужно топ-N? Используйте heapq.nsmallest/nlargest вместо полной сортировки.
- Смешение типов (числа и строки) в Python 3 сравнивать напрямую нельзя — приводите к общему типу в key.
import heapq
nums = [5, 1, 9, 3, 7]
print(heapq.nlargest(2, nums)) # [9, 7]
print(heapq.nsmallest(3, nums)) # [1, 3, 5]
Частые ошибки
- Ожидание результата от list.sort(): метод возвращает None.
- Попытка «обратить» сортировку срезом [::-1] вместо reverse=True — это два прохода и не всегда корректно с многокритериальной логикой.
- Игнорирование None: используйте кортежи в key, чтобы складывать None в конец/начало.
- Дорогие преобразования в key без кэширования — теряете производительность.
Итоги
Запомните: sorted — создаёт новый список, list.sort — сортирует на месте; key — ваш главный инструмент; сортировка стабильна и поддерживает многокритериальные ключи. Освоив эти приёмы, вы закроете 90% задач по упорядочиванию данных в Python быстро и безопасно.
Хотите системно прокачать Python с практикой и обратной связью? Попробуйте курс: Пройти «Python с Нуля до Гуру» и уверенно писать чистый, эффективный код.
-
Создано 06.03.2026 17:01:51
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.