Addaly is in open beta. Things will change, and AI answers can be wrong — check anything that matters.

Python, From Zero, For AI

From your first line of code to your first API call.

Lesson 19 of 898 min

Sorting by something other than the value itself

sorted takes a function that says what to compare

python
words = ["banana", "fig", "apple"]
sorted(words)                    # ['apple', 'banana', 'fig'] — alphabetical
sorted(words, key=len)           # ['fig', 'apple', 'banana'] — by length
sorted(words, reverse=True)      # reverse alphabetical

key is a function applied to each element; the results are what get compared. Note that len is passed without brackets — you are handing over the function itself, not calling it. key=len() is an immediate TypeError, and it is the most common mistake here.

For anything not already a function, write a lambda — a small unnamed function:

python
people = [{"name": "Asha", "age": 34}, {"name": "Ravi", "age": 28}]
sorted(people, key=lambda p: p["age"])

Read lambda p: p["age"] as "given p, produce p's age".

For the common cases the standard library has faster, clearer versions:

python
from operator import itemgetter, attrgetter
sorted(people, key=itemgetter("age"))
sorted(objects, key=attrgetter("created_at"))

Sorting by two things at once

Return a tuple. Tuples compare element by element, left first:

python
sorted(people, key=lambda p: (p["city"], p["age"]))

City ascending; within each city, age ascending. To reverse only one of them, negate a number:

python
sorted(people, key=lambda p: (p["city"], -p["age"]))

reverse=True reverses everything, which is usually not what a report wants.

For a non-numeric field you cannot negate, use the other route: Python's sort is stable, meaning equal elements keep their existing relative order. So you can sort twice, least important key first:

python
people.sort(key=itemgetter("name"))                  # tie-break
people.sort(key=itemgetter("city"), reverse=True)    # primary

Stability is a guarantee, not an implementation accident, and it is the reason this works.

sort against sorted, again

list.sort() orders the list in place and returns None. sorted(anything) returns a new list and works on any iterable — a set, a dictionary's items, a generator, a file. Sorting a dictionary by value:

python
top = sorted(counts.items(), key=itemgetter(1), reverse=True)[:10]

Case, and why sorted looks wrong on names

python
sorted(["banana", "Apple", "cherry"])
# ['Apple', 'banana', 'cherry']

Every capital letter sorts before every lowercase letter, because the comparison is on the underlying code points and A is 65 while a is 97. For a human-facing list:

python
sorted(names, key=str.lower)

str.casefold is stricter still and handles cases like the German double-s properly.

The limitation worth stating plainly

Python sorts strings by Unicode code point. That is not alphabetical order in most of the world's languages.

  • Accented characters land after all unaccented ones, so zebra sorts before Ångström.
  • Devanagari, Tamil and Bengali text sorts by code point, which is not the order any dictionary in those languages uses.
  • Sorting mixed English and Indian-language names gives an order no reader recognises.

The standard library's locale.strxfrm can do proper collation, but only if the operating system has that locale installed, which on a container or a phone it usually does not. The reliable route is the free PyICU package, which carries the Unicode collation data itself, or pyuca. If your output is going in front of readers in a language with its own alphabet, code-point order is a bug, and it is one nobody reports because it looks merely arbitrary.

Numbers hidden in strings

python
sorted(["file10.txt", "file2.txt"])
# ['file10.txt', 'file2.txt']

Character by character, 1 precedes 2, so file10 comes first. This is correct string ordering and wrong for a person. The fix is a key that splits digits from text:

python
import re
def natural(s):
    return [int(p) if p.isdigit() else p for p in re.split(r"(\d+)", s)]

sorted(["file10.txt", "file2.txt"], key=natural)

Sorting mixed types fails

python
sorted([3, "1", 2])
# TypeError: '<' not supported between instances of 'str' and 'int'

Python 3 refuses rather than inventing an order. This is almost always a message that a column read from a file was never converted, and it is better to be told now than to get a silently strange order.

Sorting is not the same as taking the top few

If you only want the largest ten of a million items, sorting the million is wasted work:

python
import heapq
top = heapq.nlargest(10, rows, key=itemgetter("score"))

nlargest keeps a heap of ten and scans once, which is roughly n log k rather than n log n. On a million rows that is a few hundred milliseconds saved, and the code says what it means.

What it costs

Python's sort is Timsort: worst case n log n, and much faster on data that is already partly ordered, which real data usually is. The key function is called exactly once per element, not once per comparison, so an expensive key is affordable.

The one thing to keep

`key` takes a function applied once per element, tuples give multi-level ordering, and stable sorting lets you order by several fields by sorting repeatedly from the least important key upwards.

Before you move on

A leaderboard must show highest score first, and for equal scores the name alphabetically. `sorted(rows, key=lambda r: (r["score"], r["name"]), reverse=True)` gives the right score order but reversed names within a tie. What is the cleanest correct fix?

Pick the one you would defend. Nobody sees your answer.

No ads. No data sale. No public scores on people. Ever.

© 2026 Addaly