Python сортировка: sort() vs sorted() – когда и что использовать
Для кого эта статья:
- Начинающие Python-разработчики, стремящиеся углубить свои знания о методах сортировки.
- Программисты, заинтересованные в оптимизации производительности кода и управлении памятью.
Студенты или участники курсов по программированию, ищущие практические примеры и рекомендации по использованию Python.
Когда я начинал работать с Python, постоянно путался в методах сортировки. Почему иногда
list.sort()возвращает None? Почемуsorted(list)создаёт копию? Такие вопросы возникают у каждого программиста. Сортировка данных — одна из фундаментальных операций, и Python предлагает два мощных инструмента: методsort()и функциюsorted(). Понимание разницы между ними не просто академический вопрос, а практическая необходимость, влияющая на производительность кода и управление памятью. 🐍
Если вы стремитесь освоить профессиональную Python-разработку, а не просто разобраться с методами сортировки, обратите внимание на Обучение Python-разработке от Skypro. Программа включает не только базовые концепции вроде сортировки данных, но и продвинутые темы — от асинхронного программирования до построения веб-приложений с Django и Flask. Вы перейдете от простых скриптов к полноценным коммерческим проектам за 9 месяцев.
Основы сортировки списков в Python
Python предлагает два основных способа сортировки списков, каждый из которых имеет свои особенности, преимущества и случаи применения. Прежде чем мы углубимся в детали, давайте рассмотрим базовый пример:
# Исходный список
numbers = [5, 2, 8, 1, 9]
# Используем sort()
numbers.sort()
print(numbers) # Результат: [1, 2, 5, 8, 9]
# Создадим новый список
numbers = [5, 2, 8, 1, 9]
# Используем sorted()
sorted_numbers = sorted(numbers)
print(sorted_numbers) # Результат: [1, 2, 5, 8, 9]
print(numbers) # Результат: [5, 2, 8, 1, 9] — исходный список не изменился
Обе функции используют алгоритм Timsort — гибрид сортировки слиянием и сортировки вставками, что обеспечивает стабильность и эффективность. Timsort был специально разработан для Python и оптимизирован для реальных данных, часто содержащих уже отсортированные последовательности. 🧠
Основные характеристики методов сортировки в Python:
| Характеристика | sort() | sorted() |
|---|---|---|
| Тип | Метод списка | Встроенная функция |
| Изменяет исходный список | Да (in-place) | Нет (создаёт копию) |
| Возвращаемое значение | None | Новый отсортированный список |
| Применим к | Только к спискам | Любым итерируемым объектам |
| Использование памяти | Эффективнее | Требует дополнительную память |
При работе с большими наборами данных выбор метода сортировки может существенно повлиять на производительность приложения и использование памяти. Если вы не планируете сохранять исходный список, sort() будет более эффективным выбором.
Дмитрий Савельев, старший Python-разработчик Однажды я столкнулся с серьёзной проблемой производительности при обработке массива с миллионами записей логов. Система анализировала пользовательскую активность и при каждой обработке создавала копии массивов через
sorted(). Память сервера быстро заканчивалась, что приводило к сбоям. После профилирования кода мы заменили все вызовыsorted()наlist.sort()там, где оригинальные данные не требовалось сохранять. Это простое изменение снизило потребление памяти на 40% и ускорило обработку на 15%. Урок прост: всегда учитывайте, нужно ли вам сохранять исходные данные, прежде чем автоматически использоватьsorted().

Метод sort(): изменение списка на месте
Метод sort() является частью класса list в Python и модифицирует список напрямую, без создания новой копии. Эта особенность делает его более эффективным в плане использования памяти, особенно при работе с объёмными наборами данных. 🔄
Вот классический пример использования sort():
fruits = ["apple", "banana", "cherry", "date"]
fruits.sort() # Сортировка по алфавиту
print(fruits) # ['apple', 'banana', 'cherry', 'date']
# sort() возвращает None
result = fruits.sort()
print(result) # None
Важно отметить, что sort() модифицирует оригинальный список и возвращает None. Это следует концепции "изменения на месте" (in-place modification) и предотвращает случайное создание цепочки методов, что могло бы вызвать путаницу.
Рассмотрим более сложные случаи использования sort():
# Сортировка списка словарей по определённому ключу
students = [
{"name": "Alex", "grade": 85},
{"name": "Maria", "grade": 92},
{"name": "Brian", "grade": 78}
]
students.sort(key=lambda student: student["grade"], reverse=True)
print(students)
# [{'name': 'Maria', 'grade': 92}, {'name': 'Alex', 'grade': 85}, {'name': 'Brian', 'grade': 78}]
Преимущества использования sort():
- Эффективность памяти: не создаёт копию списка, что критично для больших данных
- Ясность намерений: код явно показывает, что исходный список изменяется
- Удобство для списков: интуитивно понятный метод для работы именно со списками
Недостатки метода sort():
- Изменение исходных данных: невозможность сохранить оригинальный порядок
- Ограниченная применимость: работает только со списками
- Возвращает None: невозможность использования в выражениях
Функция sorted(): создание нового отсортированного списка
Функция sorted() — это встроенная функция Python, которая принимает любой итерируемый объект и возвращает новый отсортированный список, оставляя исходные данные без изменений. Эта особенность делает sorted() более гибким, но требующим больше памяти инструментом. 📦
original_tuple = (5, 2, 8, 1, 9)
sorted_list = sorted(original_tuple)
print(sorted_list) # [1, 2, 5, 8, 9]
print(original_tuple) # (5, 2, 8, 1, 9) – исходный кортеж не изменился
# Работает с любыми итерируемыми объектами
sorted_chars = sorted("hello")
print(sorted_chars) # ['e', 'h', 'l', 'l', 'o']
Одно из главных преимуществ sorted() — его способность работать с любыми итерируемыми объектами, а не только со списками. Это делает его универсальным инструментом в различных сценариях:
# Сортировка словаря по ключам
my_dict = {"c": 3, "a": 1, "b": 2}
sorted_keys = sorted(my_dict)
print(sorted_keys) # ['a', 'b', 'c']
# Сортировка словаря по значениям
sorted_by_values = sorted(my_dict.items(), key=lambda x: x[1])
print(sorted_by_values) # [('a', 1), ('b', 2), ('c', 3)]
# Сортировка множества
my_set = {5, 2, 8, 1, 9}
sorted_set = sorted(my_set)
print(sorted_set) # [1, 2, 5, 8, 9]
Елена Михайлова, руководитель команды аналитиков данных В нашем проекте по анализу потребительских предпочтений мы обрабатывали данные из нескольких источников. Ключевым требованием было сохранение оригинальных данных для аудита и параллельное создание отсортированных наборов для анализа тенденций. Изначально младший разработчик использовал метод
sort()и перед сортировкой создавал копии списков черезlist.copy(). Код выглядел громоздким:PythonСкопировать кодoriginal_data = get_customer_data() sorted_data = original_data.copy() sorted_data.sort(key=lambda x: x['purchase_amount'])После рефакторинга мы заменили это на элегантное решение с
sorted():PythonСкопировать кодoriginal_data = get_customer_data() sorted_data = sorted(original_data, key=lambda x: x['purchase_amount'])Это не только сделало код более читаемым, но и уменьшило вероятность ошибок, когда разработчики забывали сделать копию перед сортировкой. В результате мы сэкономили десятки часов на отладке и получили более надёжную систему анализа.
Сравнение sorted() с другими методами обработки данных:
| Функция | Возвращаемый тип | Изменяет исходные данные | Работает с итерируемыми |
|---|---|---|---|
| sorted() | Список | Нет | Да (любыми) |
| list.sort() | None | Да | Только списки |
| reversed() | Итератор | Нет | Да (последовательностями) |
| list.reverse() | None | Да | Только списки |
Когда следует использовать sorted():
- Когда необходимо сохранить исходные данные без изменений
- При работе с неизменяемыми (immutable) типами данных: кортежи, строки
- Когда требуется сортировать итерируемые объекты, не являющиеся списками
- В функциональном стиле программирования, где предпочтительнее использовать чистые функции без побочных эффектов
Настройка сортировки с параметрами key и reverse
Как sort(), так и sorted() поддерживают одинаковые параметры для гибкой настройки процесса сортировки. Два ключевых параметра — key и reverse — открывают огромные возможности для кастомизации сортировки под специфические задачи. 🔑
Параметр key принимает функцию, которая применяется к каждому элементу перед сравнением. Это позволяет реализовать сортировку по любым критериям:
# Сортировка строк по длине
words = ["python", "is", "awesome", "language"]
sorted_by_length = sorted(words, key=len)
print(sorted_by_length) # ['is', 'python', 'awesome', 'language']
# Сортировка чисел по их абсолютному значению
numbers = [-5, -1, 3, 2, -4]
numbers.sort(key=abs)
print(numbers) # [-1, 2, 3, -4, -5]
Часто с параметром key используются lambda-функции, особенно при работе со сложными структурами данных:
# Сортировка списка кортежей по второму элементу
data = [(1, "one"), (3, "three"), (2, "two")]
sorted_data = sorted(data, key=lambda item: item[1])
print(sorted_data) # [(1, 'one'), (3, 'three'), (2, 'two')]
# Сортировка словаря по значениям
my_dict = {"apple": 5, "banana": 2, "cherry": 8}
sorted_dict = sorted(my_dict.items(), key=lambda item: item[1])
print(sorted_dict) # [('banana', 2), ('apple', 5), ('cherry', 8)]
Для более сложных критериев сортировки можно использовать модуль operator, который предоставляет удобные функции вместо lambda-выражений:
import operator
# Сортировка списка словарей по вложенному значению
data = [
{"user": {"name": "Alice", "age": 30}},
{"user": {"name": "Bob", "age": 25}},
{"user": {"name": "Charlie", "age": 35}}
]
# С использованием lambda
sorted_data = sorted(data, key=lambda x: x["user"]["age"])
# С использованием operator.itemgetter
from operator import itemgetter
sorted_data = sorted(data, key=lambda x: itemgetter("age")(x["user"]))
print(sorted_data)
# [{'user': {'name': 'Bob', 'age': 25}},
# {'user': {'name': 'Alice', 'age': 30}},
# {'user': {'name': 'Charlie', 'age': 35}}]
Параметр reverse принимает логическое значение (True или False) и определяет порядок сортировки — по возрастанию или по убыванию:
numbers = [1, 5, 3, 9, 2]
# Сортировка по возрастанию (по умолчанию)
ascending = sorted(numbers) # [1, 2, 3, 5, 9]
# Сортировка по убыванию
descending = sorted(numbers, reverse=True) # [9, 5, 3, 2, 1]
# Также работает с sort()
numbers.sort(reverse=True)
print(numbers) # [9, 5, 3, 2, 1]
Для сортировки по нескольким критериям можно использовать кортежи в функции key:
# Сортировка студентов по классу (по возрастанию) и затем по среднему баллу (по убыванию)
students = [
{"name": "Alice", "class": 10, "grade": 85},
{"name": "Bob", "class": 9, "grade": 92},
{"name": "Charlie", "class": 10, "grade": 78},
{"name": "Diana", "class": 9, "grade": 95}
]
# Используем отрицательное значение для сортировки по убыванию
students.sort(key=lambda x: (x["class"], -x["grade"]))
print(students)
# [{'name': 'Diana', 'class': 9, 'grade': 95},
# {'name': 'Bob', 'class': 9, 'grade': 92},
# {'name': 'Alice', 'class': 10, 'grade': 85},
# {'name': 'Charlie', 'class': 10, 'grade': 78}]
Для строк в Python предусмотрены дополнительные функции, упрощающие сортировку без учета регистра:
# Сортировка строк без учета регистра
names = ["alice", "Bob", "charlie", "Diana"]
sorted_names = sorted(names, key=str.lower)
print(sorted_names) # ['alice', 'Bob', 'charlie', 'Diana']
Выбор оптимального метода сортировки для разных задач
Выбор между sort() и sorted() зависит от конкретного сценария использования. Вот практические рекомендации для типичных задач программирования: 🎯
- Используйте
sort(), когда: - Вам не нужно сохранять оригинальный порядок элементов
- Вы работаете с большими списками и хотите оптимизировать память
- Вы работаете исключительно со списками
Вам важно избежать излишнего копирования данных
- Используйте
sorted(), когда: - Необходимо сохранить исходный порядок оригинального объекта
- Вы работаете с неизменяемыми типами (кортежи, строки)
- Вам нужно сортировать словари, множества или генераторы
- Вы предпочитаете функциональный стиль без побочных эффектов
Рассмотрим примеры оптимального выбора метода сортировки для различных сценариев:
# Сценарий 1: Модификация входных данных для дальнейшей обработки
def process_data(numbers):
# Здесь лучше использовать sort(), так как нам не нужны исходные данные
numbers.sort()
return sum(numbers[1:-1]) # Сумма всех чисел, кроме минимального и максимального
# Сценарий 2: Функция, не должна изменять входные данные
def get_top_items(items, n=5):
# Здесь лучше использовать sorted(), чтобы не изменять исходный список
return sorted(items, reverse=True)[:n]
# Сценарий 3: Цепочка операций с данными
def process_chain(data):
# Использование sorted() позволяет создавать цепочки вызовов
return list(map(str, sorted(filter(lambda x: x > 0, data))))
При работе с пользовательскими классами можно определить специальные методы для поддержки сортировки:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# Определяем как сравнивать объекты
def __lt__(self, other):
return self.age < other.age
def __repr__(self):
return f"Person('{self.name}', {self.age})"
# Теперь можно сортировать напрямую
people = [Person("Alice", 30), Person("Bob", 25), Person("Charlie", 35)]
sorted_people = sorted(people) # Сортировка по возрасту
print(sorted_people) # [Person('Bob', 25), Person('Alice', 30), Person('Charlie', 35)]
# Или указать другой критерий сортировки
people.sort(key=lambda person: person.name) # Сортировка по имени
print(people) # [Person('Alice', 30), Person('Bob', 25), Person('Charlie', 35)]
Производительность — ещё один критический фактор при выборе метода сортировки. Вот сравнение производительности для различных размеров данных:
| Размер списка | sort() (время, мс) | sorted() (время, мс) | Разница в памяти |
|---|---|---|---|
| 1 000 | 0.15 | 0.18 | Незначительная |
| 10 000 | 1.8 | 2.2 | ~80 КБ |
| 100 000 | 22.5 | 27.8 | ~800 КБ |
| 1 000 000 | 260.3 | 315.6 | ~8 МБ |
Как видим, метод sort() выполняется немного быстрее и использует меньше памяти, что становится заметно при обработке больших объемов данных.
Выбор оптимального метода также зависит от стиля программирования и парадигмы:
- В функциональном программировании предпочтительнее
sorted(), так как он не имеет побочных эффектов - В объектно-ориентированном подходе часто используют
sort()для изменения внутреннего состояния объектов - В процедурном стиле выбор зависит от конкретной задачи и контекста использования
Понимание различий между
sort()иsorted()— это не просто техническая деталь, а фундаментальный навык эффективного Python-программиста. Правильный выбор метода сортировки может значительно повлиять на производительность, читаемость кода и управление памятью. Взвешивайте преимущества in-place модификации против создания новых структур данных, особенно когда работаете с большими наборами информации. Помните, что лаконичный и понятный код часто важнее микрооптимизаций — выбирайте тот подход, который делает ваши намерения максимально прозрачными для других разработчиков. 🐍
Читайте также
- Срезы списков Python: от базовых до продвинутых техник работы с данными
- 5 способов создания списков в Python: от простых до продвинутых
- Метод extend() в Python: как эффективно расширять списки данных
- Python: освой list comprehension и пиши код эффективнее – 7 техник
- 7 техник ускорения Python-кода при работе со списками – оптимизация
- 5 мощных техник объединения списков в Python: эффективный код
- Списки в Python: мощный инструмент для эффективной разработки
- Метод count() в Python: подсчет элементов в списках, строках, кортежах
- Метод index() в Python: поиск элементов в списках, строках, кортежах
- 5 способов очистки списков в Python: что работает эффективнее