Sorting in Python: The key= Parameter

· 3 min read · Updated March 12, 2026 · beginner
python sorting list lambda

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 original
  • list.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