Метод sort() для сортировки списков в Python
Метод list sort в Python упорядочивает элементы списка прямо на месте, без создания копии. Ниже разобраны параметры key и reverse, сортировка чисел, строк, кортежей и словарей, отличие от функции sorted() и типичные ошибки, из-за которых результат получается не тем, что ожидалось.

Содержание статьи
Синтаксис и поведение list.sort()
Метод вызывается у самого списка и меняет его содержимое. По умолчанию элементы выстраиваются по возрастанию: числа от меньшего к большему, строки в порядке кодов символов Unicode.
prices = [470, 120, 990, 305, 58]
prices.sort()
print(prices) # [58, 120, 305, 470, 990]Полная сигнатура выглядит так: list.sort(*, key=None, reverse=False). Звездочка означает, что оба параметра передаются только по имени. Запись prices.sort(True) вызовет TypeError, правильно писать prices.sort(reverse=True).
| Параметр | По умолчанию | Назначение |
|---|---|---|
key | None | Функция одного аргумента, результат которой используется для сравнения |
reverse | False | При True порядок становится убывающим |
Метод возвращает None, а не отсортированный список. Это сделано намеренно, чтобы было видно: изменился исходный объект. Если нужна новая последовательность, а оригинал должен остаться прежним, используют функцию sorted().
Сортировка по убыванию
Для обратного порядка достаточно передать reverse=True. Параметр работает с любым типом элементов, которые умеют сравниваться между собой.
scores = [72, 95, 64, 88]
scores.sort(reverse=True)
print(scores) # [95, 88, 72, 64]
letters = ['e', 'a', 'u', 'o', 'i']
letters.sort(reverse=True)
print(letters) # ['u', 'o', 'i', 'e', 'a']Не путайте reverse=True с методом reverse(). Первый сортирует по убыванию, второй просто переворачивает текущий порядок элементов, ничего не сравнивая. Другие методы и их отличия собраны в обзоре методов списка.
Параметр key: собственный критерий сравнения
Функция из key вызывается один раз для каждого элемента. Python сравнивает уже полученные ключи, а в список кладет исходные значения. Подойдет встроенная функция, метод, обычная функция или лямбда.
Строки по длине и без учета регистра
Заглавные латинские буквы имеют меньшие коды, чем строчные, поэтому без ключа 'Zebra' окажется раньше 'apple'. Ключ str.lower выравнивает регистр только для сравнения.
words = ['banana', 'Kiwi', 'apple', 'Fig']
words.sort()
print(words) # ['Fig', 'Kiwi', 'apple', 'banana']
words.sort(key=str.lower)
print(words) # ['apple', 'banana', 'Fig', 'Kiwi']
words.sort(key=len)
print(words) # ['Fig', 'Kiwi', 'apple', 'banana']Кортежи и словари
Кортежи без ключа сравниваются поэлементно: сначала первые элементы, при равенстве вторые и так далее. Чтобы сортировать по конкретному полю, его возвращают из лямбды. Синтаксис анонимных функций подробно описан в статье про lambda в Python.
points = [(2, 2), (3, 4), (4, 1), (1, 3)]
points.sort(key=lambda p: p[1])
print(points) # [(4, 1), (2, 2), (1, 3), (3, 4)]
employees = [
{'name': 'Alan', 'age': 25, 'salary': 10000},
{'name': 'Sharon', 'age': 30, 'salary': 8000},
{'name': 'John', 'age': 18, 'salary': 1000},
]
employees.sort(key=lambda e: e['salary'], reverse=True)
print([e['name'] for e in employees]) # ['Alan', 'Sharon', 'John']Список словарей нельзя отсортировать без ключа: словари не поддерживают операцию <, и Python выбросит TypeError. Если же задача в том, чтобы упорядочить сам словарь по ключам или значениям, это разобрано отдельно в материале о сортировке словаря.
Функции модуля operator
Вместо лямбд можно использовать itemgetter и attrgetter. Они работают чуть быстрее и умеют принимать несколько полей сразу.
from operator import itemgetter
rows = [('Ivan', 'B', 90), ('Olga', 'A', 85), ('Petr', 'A', 92)]
rows.sort(key=itemgetter(1, 2))
print(rows)
# [('Olga', 'A', 85), ('Petr', 'A', 92), ('Ivan', 'B', 90)]Сортировка по нескольким полям
Чтобы упорядочить данные сначала по одному признаку, а при совпадении по другому, ключ возвращает кортеж. Для числовых полей обратный порядок удобно получить сменой знака.
students = [('Anna', 5, 19), ('Boris', 4, 20), ('Vera', 5, 18)]
# оценка по убыванию, затем возраст по возрастанию
students.sort(key=lambda s: (-s[1], s[2]))
print(students)
# [('Vera', 5, 18), ('Anna', 5, 19), ('Boris', 4, 20)]Со строками минус не сработает. Здесь помогает стабильность сортировки: элементы с одинаковым ключом сохраняют исходный взаимный порядок. Поэтому можно сортировать в несколько проходов, начиная со второстепенного признака и заканчивая главным.
staff = [('Lee', 'IT'), ('Adams', 'HR'), ('Brown', 'IT'), ('Clark', 'HR')]
staff.sort(key=lambda s: s[0]) # имя по возрастанию
staff.sort(key=lambda s: s[1], reverse=True) # отдел по убыванию
print(staff)
# [('Brown', 'IT'), ('Lee', 'IT'), ('Adams', 'HR'), ('Clark', 'HR')]Внутри CPython работает алгоритм на основе Timsort со сложностью O(n log n). На почти упорядоченных данных он заметно быстрее, потому что находит уже отсортированные участки и сливает их.
Чем sort() отличается от sorted()
Оба инструмента принимают одинаковые key и reverse и дают один и тот же порядок. Разница в том, что происходит с исходными данными и что возвращается.
list.sort() | sorted() | |
|---|---|---|
| Где определен | Метод списка | Встроенная функция |
| Исходные данные | Изменяются | Остаются без изменений |
| Результат | None | Новый список |
| Что принимает | Только список | Любой итерируемый объект: кортеж, строку, множество, словарь |
| Память | Копия не создается | Нужна память под новый список |
data = [3, 1, 2]
result = sorted(data)
print(data, result) # [3, 1, 2] [1, 2, 3]
print(sorted('python')) # ['h', 'n', 'o', 'p', 't', 'y']Если исходный список дальше не нужен, выбирайте sort(): экономится память. Если оригинал нужно сохранить или на входе не список, берите sorted(). Больше приемов работы с этим типом данных есть в разделе о работе со списками.
Типичные ошибки при сортировке
Большинство проблем связано с тем, что ожидания от сравнения элементов не совпадают с тем, как сравнивает Python.
new = items.sort()записывает в переменнуюNone. Сортируйте отдельной строкой или используйтеsorted().- Смешанные типы.
[3, 'a', 1].sort()падает с ошибкойTypeError: '<' not supported between instances of 'str' and 'int'. - Числа в виде строк сравниваются посимвольно:
['10', '9', '2']превратится в['10', '2', '9']. Нуженkey=int. - Буква ё. Ее код больше, чем у я, поэтому слова на ё уходят в конец. Простой выход:
key=lambda w: w.lower().replace('ё', 'е'). Noneсреди чисел тоже вызываетTypeError. Такие значения отфильтровывают заранее или задают ключ вродеlambda x: (x is None, x or 0).
nums = ['10', '9', '2', '33']
nums.sort(key=int)
print(nums) # ['2', '9', '10', '33']
cities = ['Ёлкино', 'Анапа', 'Яхрома']
cities.sort(key=lambda w: w.lower().replace('ё', 'е'))
print(cities) # ['Анапа', 'Ёлкино', 'Яхрома']Дополнительные примеры и разбор порядка сравнения есть в официальном руководстве Sorting Techniques.
Частые вопросы
Ответы на вопросы, которые возникают при первом знакомстве с сортировкой списков.
Почему print(lst.sort()) выводит None?
Метод меняет список на месте и ничего не возвращает. Сначала вызовите lst.sort(), затем отдельно print(lst), либо выведите sorted(lst).
Можно ли отсортировать кортеж или строку методом sort()?
Нет, у неизменяемых типов этого метода нет. Функция sorted() принимает их и возвращает список, а строку обратно можно собрать через ''.join(sorted(s)).
Как отсортировать список по убыванию без reverse?
Для чисел подойдет ключ key=lambda x: -x. Но reverse=True короче, понятнее и работает с любыми типами, включая строки.
Сохраняется ли порядок одинаковых элементов?
Да, сортировка в Python стабильная, в том числе при reverse=True. Элементы с равными ключами остаются в той же последовательности, в какой были до вызова.
Что быстрее, sort() или sorted()?
Алгоритм одинаковый, но sorted() сначала копирует данные. На больших списках sort() немного выигрывает по времени и памяти.