Sorting in Python: The key= Parameter
The Basics
Python gives you two ways to sort: sorted() returns a new list, while list.sort() sorts in place. Both accept a key= parameter that lets you control how elements are compared.
By default, Python sorts by the natural order of elements:
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_numbers = sorted(numbers)
print(sorted_numbers) # [1, 1, 2, 3, 4, 5, 6, 9]
The key parameter accepts a function that takes one argument and returns the value to sort by. Here’s how to sort strings by length:
words = ["apple", "pie", "a", "banana"]
sorted_by_length = sorted(words, key=len)
print(sorted_by_length) # ['a', 'pie', 'apple', 'banana']
Lambda Functions as Keys
For simple transformations, lambda functions work well:
students = [
{"name": "Alice", "score": 85},
{"name": "Bob", "score": 92},
{"name": "Charlie", "score": 78}
]
# Sort dictionaries by a specific field
by_score = sorted(students, key=lambda s: s["score"])
# [{'name': 'Charlie', 'score': 78}, {'name': 'Alice', 'score': 85}, {'name': 'Bob', 'score': 92}]
by_name = sorted(students, key=lambda s: s["name"])
# [{'name': 'Alice', 'score': 85}, {'name': 'Bob', 'score': 92}, {'name': 'Charlie', 'score': 78}]
Lambdas are convenient for one-off sorting tasks. But when you’re sorting the same way in multiple places, operator.itemgetter and operator.attrgetter are worth knowing.
Using operator.itemgetter
When sorting by dictionary keys or tuple indices, itemgetter is faster than a lambda:
from operator import itemgetter
# Same as lambda x: x["score"]
by_score = sorted(students, key=itemgetter("score"))
# Sort by tuple index
pairs = [(1, "one"), (3, "three"), (2, "two")]
sorted_pairs = sorted(pairs, key=itemgetter(0))
# [(1, 'one'), (2, 'two'), (3, 'three')]
# Can extract multiple values
get_name_score = itemgetter("name", "score")
print(get_name_score(students[0])) # ('Alice', 85)
The performance difference matters when sorting large lists, since itemgetter is implemented in C.
Using operator.attrgetter
For objects with attributes, attrgetter does the same thing:
from operator import attrgetter
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
products = [
Product("Widget", 29.99),
Product("Gadget", 49.99),
Product("Thingamajig", 19.99)
]
sorted_by_price = sorted(products, key=attrgetter("price"))
sorted_by_name = sorted(products, key=attrgetter("name"))
You can also chain attributes for nested access:
# Sort by employee's department name
sorted_employees = sorted(employees, key=attrgetter("department.name"))
Sorting with Multiple Keys
Sometimes one sort key isn’t enough. Imagine sorting products by category first, then by price within each category:
products = [
{"name": "Apple", "category": "fruit", "price": 1.50},
{"name": "Banana", "category": "fruit", "price": 0.75},
{"name": "Carrot", "category": "vegetable", "price": 1.00},
{"name": "Apple", "category": "vegetable", "price": 2.00},
]
# Sort by category, then by price
sorted_products = sorted(products, key=lambda p: (p["category"], p["price"]))
The key function returns a tuple. Python sorts tuples lexicographically—it compares the first element, then the second if there’s a tie, and so on.
You can combine this with itemgetter for cleaner code:
sorted_products = sorted(products, key=itemgetter("category", "price"))
Descending Order
Both sorted() and list.sort() accept a reverse parameter:
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
descending = sorted(numbers, reverse=True)
print(descending) # [9, 6, 5, 4, 3, 2, 1, 1]
You can combine reverse with any key function:
# Longest words first
sorted_words = sorted(words, key=len, reverse=True)
When to Use sorted() vs list.sort()
sorted()returns a new list—useful when you need to keep the originallist.sort()modifies in place—saves memory when you don’t need the original
Both have the same key and reverse parameters, so the choice is just about whether you need immutability.
# Original stays intact
new_list = sorted(original_list, key=len)
# Sorts in place, returns None
original_list.sort(key=len)
See Also
- Lambda Functions in Python — Anonymous functions that pair perfectly with key= parameters
- Python List Methods — Complete reference for list operations including sort()
- Working with Dictionaries — Understanding dict structure for itemgetter sorting