Sorting and comprehensions
Putting a list in order, and building a new one from an old one — the two lines that replace a lot of loops.
Sorted makes a new list
sorted(words) hands back a new list in order and leaves the original alone; the list method words.sort() reorders the list itself. Reaching for sorted first is the habit that avoids the bug where a function quietly rearranges the caller’s data.
key= names what to sort by. sorted(words, key=len) orders by length, shortest first; sorted(recipes, key=minutes) orders by whatever a small function returns for each item — one function, and the ordering can be anything you can calculate.
Two orders, same list
words = ["banana", "fig", "cherry", "apple"]
print(sorted(words))
print(sorted(words, key=len))
recipes = [{"name": "Soup", "minutes": 40}, {"name": "Toast", "minutes": 5}]
print(sorted(recipes, key=lambda recipe: recipe["minutes"]))A loop that builds a list, in one line
A comprehension is a loop that collects its results. [word.upper() for word in words] walks the list and builds a new one, in the same order — the same work as a for loop with an append, written where the list is used instead of four lines away.
Add a condition at the end and it filters while it builds: [word for word in words if len(word) > 4] keeps only the long ones. The result is always a new list; the old one is untouched.
Dictionaries are built the same way
Curly braces with a key and a value do the same for dictionaries: {word: len(word) for word in words} is a lookup table from each word to its length. One line, and the shape of the data explains itself.
Comprehensions stop being readable when they try to do three things at once. When one needs a comment to explain itself, it wants to be a loop again.
Shortest first, then first letters
Sort the words by length, shortest first, and print the first letter of each word as one joined string using a list comprehension.
Text sorts by character, numbers by value
sorted compares items with <, and what that means depends on the type. Numbers compare by size, so 9 comes before 10. Text compares character by character, so "10" comes before "9" because the character 1 precedes 9. A list of numbers stored as text therefore sorts into an order that looks wrong and is technically correct.
The fix is to sort by a key that returns a number: key=int for text that holds whole numbers, or key=float for prices. The same idea applies to dates written as text in a format that does not sort — convert first, then order.
A comprehension is an expression, not a loop
The result of a comprehension is a value, so it can be printed, returned, or passed straight into another call. It cannot contain a print statement in the middle, and it should not try: a comprehension that exists for its side effects is a loop wearing the wrong shape.
When the body needs more than one step, write the loop. The four-line version is not a failure; it is the version a reader can put a breakpoint in. Use the short form when the transformation fits in one expression, and stop when it does not.
key=len passes the function itself, without brackets. With brackets you would be calling it and sorting by the result for every item at once, which is almost never what you meant.
The key is calculated, then compared
sorted(items, key=...) runs the key function once for each item and sorts by the results. The original values are not changed, and the key does not have to return text — any values that can be compared with each other work.
Sorting is stable: when two keys tie, the items keep their original order. That is why sorting by one field and then by another can build a multi-level order, and why reverse=True flips the comparison without shuffling ties.
What a comprehension does, in order
A comprehension reads in two parts: the expression before for says what each new item is, and the if at the end says which originals qualify. The condition is checked before the expression runs.
That order matters when the expression is expensive or could fail: a filtered comprehension never evaluates it for a rejected item. It is also why the result is a new list rather than a changed one.
Three sorting mistakes: key=len() calls the function immediately instead of passing it, which is a TypeError; words.sort() returns None, so sorted_words = words.sort() throws the list away; and sorting a mix of text and numbers raises TypeError because Python will not guess an order between them.
Try these next
- Sort a list of names by length, then alphabetically, and compare the orders.
- Sort numbers with
reverse=True, then compare that withsorted(numbers)[::-1]; they should match. - Write
key=len()once, read the error, and remove the brackets.
Rank the runners
Sort the runners by their time, fastest first, and print each one with a place number. Then add a fourth runner and check the places still start at 1.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What is the difference between sorted(words) and words.sort()?
