Є баг, який хоч раз ловить майже кожен, хто вчить Python. Пишеш numbers = numbers.sort(), запускаєш — і в numbers лежить None. Список ніби відсортувався — і тут же зник.

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 1

Python тут ні до чого, він зробив рівно те, що йому сказали. Просто sort і sorted виглядають як близнюки, а поводяться по-різному. Розберімося раз і назавжди — а заразом пройдемо все, що трапляється на практиці: ключі, словники, обʼєкти, кілька полів, кирилицю і швидкість.

Чим sorted відрізняється від sort

Якщо зовсім коротко: sorted() — це функція, яка повертає новий відсортований список і не чіпає вихідні дані. list.sort() — це метод списку, який сортує його на місці й повертає None.

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 2
scores = [42, 7, 19]

fresh = sorted(scores)
print(scores)  # [42, 7, 19] — вихідний список не змінився
print(fresh)   # [7, 19, 42] — це новий список

fresh = scores.sort()
print(scores)  # [7, 19, 42] — тепер змінився сам список
print(fresh)   # None

Ось і розгадка бага з початку: .sort() відпрацював, відсортував список, повернув None — і цей None записався поверх списку. Повернення None — свідоме рішення авторів Python: метод, який змінює обʼєкт, нічого не повертає, щоб ніхто не сплутав його з функцією, що створює копію.

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 3
sorted()list.sort()
Що цевбудована функціяметод списку
Що повертаєновий списокNone
Вихідні даніне змінюютьсязмінюються
З чим працюєбудь-який ітерований обʼєкт: список, кортеж, рядок, словник, множиналише список
Коли братипотрібен оригінал або в тебе не списоксписок великий, оригінал не потрібен

Важлива деталь: sorted() завжди повертає список, що б ти йому не дав.

sorted((3, 1, 2))       # [1, 2, 3] — з кортежу вийшов список
sorted("python")        # ['h', 'n', 'o', 'p', 't', 'y']
"".join(sorted("python"))  # 'hnopty'

Сортування за спаданням: reverse

В обох інструментів однакові параметри: key і reverse. Передавати їх можна лише за іменем — numbers.sort(True) видасть TypeError.

cities = ["Одеса", "Варшава", "Мадрид"]

sorted(cities)                # ['Варшава', 'Мадрид', 'Одеса']
sorted(cities, reverse=True)  # ['Одеса', 'Мадрид', 'Варшава']

Сортування за ключем: параметр key

key — головний параметр сортування. Ти передаєш функцію, Python викликає її для кожного елемента й сортує за тим, що вона повернула. Самі елементи при цьому не змінюються.

Візьмімо список співробітників — далі працюватимемо з ним:

employees = [
    {"name": "Марта", "dept": "Dev", "salary": 4200},
    {"name": "Денис", "dept": "QA", "salary": 2600},
    {"name": "Ліза", "dept": "Dev", "salary": 3100},
    {"name": "Карина", "dept": "Design", "salary": 2900},
]

lambda — для швидких ключів

by_salary = sorted(employees, key=lambda e: e["salary"])

itemgetter і attrgetter — те саме, але швидше

У модулі operator є готові функції для доступу до поля словника й атрибута обʼєкта. Вони написані на C, тому працюють швидше за lambda.

from operator import itemgetter

by_salary = sorted(employees, key=itemgetter("salary"))

Наскільки швидше? Ми заміряли на свіжому Python 3.15 і ста тисячах словників: itemgetter обігнав lambda приблизно на 10%. Приємно, але не революція — на коротких списках різниці не помітиш. Бери itemgetter, коли сортуєш багато й часто, і lambda — коли так зрозуміліше.

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 4

Готові функції та методи

У key можна передати будь-яку функцію з одним аргументом, зокрема вбудовану. Головне — передавати саму функцію, без дужок.

words = ["banana", "kiwi", "Cherry"]

sorted(words)                 # ['Cherry', 'banana', 'kiwi'] — великі літери йдуть раніше
sorted(words, key=str.lower)  # ['banana', 'Cherry', 'kiwi'] — без урахування регістру
sorted(words, key=len)        # ['kiwi', 'banana', 'Cherry'] — за довжиною

Сортування за кількома полями

Ключ-кортеж

Якщо key повертає кортеж, Python порівнює його поелементно: спершу перше значення, за рівності — друге і так далі. Щоб одне з числових полів ішло за спаданням, ставимо перед ним мінус.

# за відділом, усередині відділу — за зарплатою від більшої до меншої
result = sorted(employees, key=lambda e: (e["dept"], -e["salary"]))

Два проходи — коли мінус не поставиш

Мінус працює лише з числами. Якщо за спаданням треба відсортувати рядок, рятує стабільність: сортування в Python ніколи не змінює порядок елементів з однаковим ключем. Тому можна відсортувати у два проходи — спершу за другорядним полем, потім за головним.

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 5
from operator import itemgetter

# 1. другорядне поле: зарплата за спаданням
step1 = sorted(employees, key=itemgetter("salary"), reverse=True)
# 2. головне поле: відділ за алфавітом — порядок зарплат усередині відділу збережеться
result = sorted(step1, key=itemgetter("dept"))

Прийнято вважати, що кортеж швидший, адже прохід один. Ми перевірили на тих самих ста тисячах словників — і два проходи з itemgetter виявилися швидшими за кортеж із lambda приблизно в півтора раза: 16 мілісекунд проти 27. Створити сто тисяч кортежів і порівнювати їх поелементно теж не безкоштовно. Мораль проста: обирай те, що читається зрозуміліше, а про швидкість думай, коли замір показав проблему.

Як відсортувати словник

Сам словник відсортувати не можна, зате можна отримати відсортовані ключі чи пари й зібрати з них новий словник — з Python 3.7 словники зберігають порядок вставлення.

grades = {"Тимур": 72, "Віра": 95, "Олег": 88}

sorted(grades)  # ['Віра', 'Олег', 'Тимур'] — лише ключі

# за значенням, від більшого до меншого
top = dict(sorted(grades.items(), key=lambda kv: kv[1], reverse=True))
print(top)  # {'Віра': 95, 'Олег': 88, 'Тимур': 72}

Потрібні лише найкращі N? Не сортуй усе

Часта задача — знайти топ-10 найбільших значень. Перше, що спадає на думку: відсортувати й узяти зріз. Але сортувати мільйон елементів заради десяти — марнотратно. Для цього є модуль heapq:

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 6
import heapq

top10 = heapq.nlargest(10, numbers)
cheapest = heapq.nsmallest(3, products, key=lambda p: p["price"])

У нашому замірі на списку з мільйона чисел heapq.nlargest(10, ...) виявився майже у 18 разів швидшим, ніж sorted(...)[:10]: 6 мілісекунд проти 103.

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 7

Сортування обʼєктів

Якщо дані лежать в обʼєктах, ключ будується так само, лише через attrgetter:

from dataclasses import dataclass
from operator import attrgetter

@dataclass
class Employee:
    name: str
    salary: int

staff = [Employee("Марта", 4200), Employee("Денис", 2600)]
sorted(staff, key=attrgetter("salary"))

А якщо обʼєкти треба сортувати завжди однаково, навчи їх порівнюватися: для dataclass достатньо @dataclass(order=True) — порівняння піде за полями в порядку оголошення.

Пʼять пасток, на яких ламається сортування

1. None у списку

sorted([3, None, 1])
# TypeError: '<' not supported between instances of 'NoneType' and 'int'

Python 3 не вміє порівнювати None з числами. Рішення — ключ, який відправляє None у кінець:

sorted([3, None, 1], key=lambda x: (x is None, x))  # [1, 3, None]

2. Різні типи

sorted([3, "2", 1]) впаде з тією самою помилкою: рядок із числом порівняти не можна. Зазвичай це означає, що дані прийшли «брудними», наприклад із CSV. Зводь до одного типу до сортування, а не всередині нього.

3. Числа всередині рядків

files = ["file10.txt", "file2.txt", "file1.txt"]
sorted(files)  # ['file1.txt', 'file10.txt', 'file2.txt']

Рядки порівнюються посимвольно, і «1» у «10» менша за «2». Щоб отримати звичний людині порядок — так зване природне сортування, — розбий рядок на текст і числа:

import re

def natural_key(s):
    return [int(part) if part.isdigit() else part.lower()
            for part in re.split(r"(\d+)", s)]

sorted(files, key=natural_key)  # ['file1.txt', 'file2.txt', 'file10.txt']
sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 8

4. Літери «є», «і», «ї», «ґ»

А ось пастка, про яку в англомовних туторіалах не пишуть:

sorted(["їжак", "яблуко", "ґанок", "гора"])  # ['гора', 'яблуко', 'їжак', 'ґанок']

Ґанок опинився в самому кінці, після яблука. Python порівнює рядки за кодами символів Unicode, а «є», «і», «ї» і «ґ» стоять у таблиці не в ряду «а»–«я», а після «я». З великими літерами те саме: «Я» йде раніше за малу «а».

Для сортування за правилами мови є модуль locale:

import locale

locale.setlocale(locale.LC_COLLATE, "uk_UA.UTF-8")
sorted(["їжак", "яблуко", "ґанок", "гора"], key=locale.strxfrm)  # ['гора', 'ґанок', 'їжак', 'яблуко']

Нюанс: результат залежить від того, які локалі встановлені в системі, а на Windows вони називаються інакше. Якщо сортувати по-людськи потрібно в продакшені, надійніша бібліотека PyICU — вона однаково працює всюди.

5. Присвоєння результату sort

Той самий баг із початку. x = x.sort() — це завжди None. Або x.sort() окремим рядком, або x = sorted(x).

Що під капотом

Сортування в Python — не навчальна «бульбашка», а гібридний алгоритм, заточений під реальні дані. З версії 2.3 це був Timsort, а з Python 3.11 його схему злиттів замінили на Powersort — надійнішу, з доведеними гарантіями.

sorted і sort у Python: у чому різниця і як сортувати списки, словники та обʼєкти - 9

Що важливо знати на практиці:

  • Складність — O(n log n) у найгіршому випадку.
  • Сортування стабільне, і це гарантовано документацією. На цьому тримається трюк із двома проходами.
  • Майже відсортовані дані сортуються дуже швидко. Алгоритм знаходить уже впорядковані шматки й просто склеює їх. У нашому замірі вже відсортований список із мільйона чисел сортувався приблизно в 9 разів швидше, ніж перемішаний.

Усі заміри ми робили на Python 3.15.1, на ноутбуці з Apple Silicon. На іншому залізі абсолютні цифри будуть іншими, але порядок співвідношень зазвичай зберігається. Захочеш перевірити в себе — вистачить модуля timeit і пʼяти рядків коду.

Навіщо це знати, якщо код пише AI

Слушне запитання. Попроси будь-яку нейромережу відсортувати список словників за зарплатою — отримаєш робочий код за секунду. Але AI з тією самою впевненістю напише data = data.sort(), не подумає про None у даних із бази й відсортує прізвища на «Ґ» чи «Є» не туди. Код виглядатиме правильно й пройде побіжний погляд.

Помітити таку помилку може лише той, хто розуміє, як працює сортування. У цьому й різниця між тим, хто користується AI, і тим, кого AI робить у рази сильнішим: інструмент прискорює того, хто має фундамент.

Фундамент Python будується на практиці, а не на читанні. На курсі Python у JavaRush це 52+ рівні задач із миттєвою перевіркою і ще 10 рівнів з алгоритмів і структур даних — де сортування розбирають не на рівні «виклич sorted», а зсередини. Якщо не знаєш, з чого почати шлях у Python загалом, зазирни в наш роадмап Python-розробника 2026.

Часті запитання

У чому різниця між sort і sorted у Python? sorted() — вбудована функція: приймає будь-який ітерований обʼєкт і повертає новий відсортований список, не змінюючи вихідні дані. list.sort() — метод списку: сортує список на місці й повертає None.

Чому list.sort() повертає None? Це свідоме рішення авторів Python: методи, які змінюють обʼєкт на місці, повертають None, щоб їх не плутали з функціями, що створюють новий обʼєкт. Тому x = x.sort() записує в змінну None.

Як відсортувати список за спаданням у Python? Передати параметр reverse=True: sorted(data, reverse=True) або data.sort(reverse=True).

Як відсортувати словник за значенням у Python? Відсортувати пари за другим елементом і зібрати новий словник: dict(sorted(d.items(), key=lambda kv: kv[1])). Для спадання додати reverse=True.

Як відсортувати список за кількома полями? Передати в key функцію, яка повертає кортеж: key=lambda e: (e["dept"], -e["salary"]). Якщо поле не можна розвернути мінусом, наприклад рядок, відсортувати у два проходи: спершу за другорядним полем, потім за головним — стабільність сортування збереже порядок.

Який алгоритм сортування використовує Python? До версії 3.10 включно — Timsort, з Python 3.11 — його покращений варіант Powersort. Обидва гібридні, стабільні, працюють за O(n log n) і особливо швидкі на частково впорядкованих даних.