Historical Context & Motivation
Sorting is one of the oldest and most studied problems in computer science. From the earliest days of computing, programmers needed ways to arrange data in a meaningful order — alphabetizing names, ranking scores, or organizing files by date. Early sorting required writing dozens of lines of code, and customizing the sort order was even harder.
Python's sorted() function was designed to make sorting simple, readable, and powerful. It builds on decades of algorithm research — particularly the development of Timsort, a hybrid sorting algorithm created by Tim Peters specifically for Python. The key parameter was introduced to let programmers define custom sorting rules without rewriting the sort itself.
key parameter.sorted() function with key and reverse parameters, replacing the older and less readable cmp approach.cmp parameter entirely, making key the standard way to customize sorting — a cleaner, more Pythonic design.The central question this lesson addresses is: how do you sort data by something other than the default order? What if you want to sort words by their length, students by their grade, or products by price? The key parameter gives you that power in a single, clean line of Python.
Core Principles & Definitions
Before diving into examples, you need to understand a few foundational ideas about how sorted() works. Unlike the .sort() method which modifies a list in place, sorted() always returns a new list and leaves the original data unchanged. This makes it safe to use anywhere without worrying about side effects.
The sorted() Function
sorted(iterable, key=None, reverse=False)The key Parameter
The reverse Parameter
True, the sort order flips from ascending (smallest first) to descending (largest first).Stability in Sorting
Lambda Functions
lambda. They're commonly used as key functions because they're compact: lambda x: len(x)key function like a label maker. Imagine you have a pile of backpacks to arrange by weight. You don't rearrange the contents — you just stick a weight label on each one, sort by the labels, then line up the original backpacks in that order. The key function creates those temporary labels for sorting, but the items in your output list remain exactly as they were.Visual Explanation
The diagram below shows how sorted() with a key function works step by step. The original list of words is transformed by the key function (len), sorted by those transformed values, and then the original elements are returned in the new order.
len) is applied to each element to produce a temporary sorting key. Elements are sorted by these keys, then the original elements (not the keys) are returned.Notice something important in the diagram: the key function is applied to every element exactly once. Python does not call the key function repeatedly during comparisons. Instead, it creates a decorated version of the list, sorts that, then strips the decorations away. This is both efficient and elegant.
How It Works Under the Hood
Understanding the full signature of sorted() helps you use it with confidence. The function signature is straightforward, and each parameter has a clear role.
The Decorate-Sort-Undecorate Pattern
Internally, Python uses a pattern called decorate-sort-undecorate (also known as the Schwartzian transform in other languages). Here is how it works in three phases:
- Decorate: For each element
xin the iterable, computekey(x)and pair it with the original element to form(key(x), x). - Sort: Sort the pairs by the first value (the key) using Timsort.
- Undecorate: Extract the original elements from the sorted pairs and return them as the final list.
Common Key Functions
| Key Function | What It Does | Example |
|---|---|---|
key=len | Sorts by the length of each element | sorted(["hi", "hello", "hey"], key=len) |
key=str.lower | Case-insensitive alphabetical sort | sorted(["Banana", "apple"], key=str.lower) |
key=abs | Sorts by absolute value (distance from zero) | sorted([-5, 3, -1, 4], key=abs) |
key=lambda x: x[1] | Sorts tuples/lists by their second element | sorted([("A", 3), ("B", 1)], key=lambda x: x[1]) |
key=lambda s: s.split()[-1] | Sorts strings by their last word | sorted(["John Smith", "Ada Lovelace"], key=lambda s: s.split()[-1]) |
Sorting Complex Data Structures
The real power of key functions emerges when you work with complex data structures — lists of dictionaries, lists of tuples, or lists of custom objects. In real-world programs, you rarely sort simple lists of numbers. Instead, you sort records with multiple fields, and you need to choose which field to sort by.
key=lambda s: (-s["grade"], s["name"]) sorts by grade descending (using negation) and then by name ascending, all in one call. The negative sign trick only works with numbers, though.Worked Example
Let's walk through a complete, realistic example. Suppose you have a list of video games with their titles and ratings, and you want to display them sorted from highest to lowest rating.
games = [("Zelda", 9.7), ("Minecraft", 9.2), ("Fortnite", 8.5), ("Elden Ring", 9.5), ("Among Us", 8.0)]("Zelda", 9.7). We want to sort by the rating, which is at index 1. Our key function will be lambda game: game[1]. This extracts the second element of each tuple.reverse=True. Without this, the default is ascending — lowest first.ranked = sorted(games, key=lambda game: game[1], reverse=True)[("Zelda", 9.7), ("Elden Ring", 9.5), ("Minecraft", 9.2), ("Fortnite", 8.5), ("Among Us", 8.0)]games list is still in its original order. sorted() created a new list called ranked without modifying the input.key=lambda game: game[1]() with parentheses after game[1]. The value 9.7 is a float, not a function — you can't call it. Also, don't write key=len() — pass the function itself (key=len), not the result of calling it.sorted() vs .sort() and Other Approaches
Python offers several ways to sort data. Understanding when to use each approach is part of becoming a skilled programmer. The two main options are the built-in sorted() function and the list method .sort(). They share the same key and reverse parameters but behave differently in important ways.
| Feature | sorted(iterable) | list.sort() |
|---|---|---|
| Returns | A new sorted list | None (modifies list in place) |
| Input types | Any iterable (list, tuple, string, dict, set, generator) | Lists only |
| Original data | Unchanged (safe) | Overwritten (destructive) |
| Memory | Uses extra memory for the new list | Sorts in place — more memory efficient |
| Chaining | Can be chained: sorted(data, key=len)[0] | Cannot chain (returns None) |
| Best for | When you need the original + sorted version, or sorting non-list iterables | When you only need the sorted version and want to save memory |
sorted() like making a photocopy of a document and then rearranging the copy — your original stays safe in the drawer. Think of .sort() like rearranging the pages of the original document itself. Use sorted() when in doubt — it's safer and more flexible.Connection to Advanced Concepts
The key parameter in sorted() is your first encounter with a powerful programming concept: higher-order functions — functions that accept other functions as arguments. This idea appears throughout Python and computer science more broadly.
| This Lesson | Advanced Concept | Connection |
|---|---|---|
key=lambda x: x[1] | Higher-order functions | Passing functions as arguments is foundational in functional programming |
key=len | map(), filter() | These built-in functions also accept a function as their first argument |
| Sort stability | Merge sort, Timsort internals | Understanding why stability matters leads to studying sorting algorithms |
| O(n log n) complexity | Big-O analysis | Knowing that sorting is O(n log n) is foundational to algorithm analysis |
| Lambda expressions | Closures, decorators | Lambdas are a stepping stone to more advanced function techniques in Python |
As you advance in computer science, you'll encounter the operator module, which provides functions like operator.itemgetter() and operator.attrgetter() as faster, more readable alternatives to lambda functions for common key patterns. You'll also learn about custom comparison methods like __lt__ that let your own classes define how their instances should be sorted.
Practice Problems
sorted(words) and sorted(words, key=len)? Explain what each call sorts by and why the results would differ for the list ["banana", "fig", "cherry", "apple"].nums = [15, -3, 8, -12, 4]
result = sorted(nums, key=abs)
print(result)students = [("Emma", 91), ("Liam", 85), ("Sophia", 91), ("Noah", 78)]
Write a single sorted() call that sorts students by score from highest to lowest. For students with the same score, sort alphabetically by name (ascending).songs = [
{"title": "Blinding Lights", "artist": "The Weeknd", "plays": 3200},
{"title": "Levitating", "artist": "Dua Lipa", "plays": 2800},
{"title": "Stay", "artist": "The Kid LAROI", "plays": 3200},
{"title": "Peaches", "artist": "Justin Bieber", "plays": 1500}
]
Write code to display the top songs sorted by play count (most played first). For songs with equal plays, sort alphabetically by title.words = ["Banana", "apple", "Cherry"]
result = sorted(words, key=str.upper, reverse=True)
Another classmate argues that key=str.lower should be used instead. Does it matter? Would the output differ? Also, explain why the original strings in the result are mixed-case even though the key converts them. What would happen if someone accidentally wrote key=str.upper() instead?Summary
Python's sorted() function returns a new sorted list from any iterable without modifying the original data. The key parameter accepts a function that transforms each element into a comparison value — like key=len for sorting by length or key=lambda x: x[1] for sorting by the second element of a tuple. The reverse=True parameter flips the order from ascending to descending.
Key functions are called exactly once per element (not during every comparison), making them efficient at O(n) key evaluations plus O(n log n) comparisons. Python's stable sort guarantees that equal elements keep their original order, enabling multi-level sorting through either tuple keys or successive sort passes. Mastering sorted() with key functions is your gateway to higher-order functions and functional programming patterns throughout Python.