Skip to Content
Course content

184: The operator Module

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this specific mistake dozens of times when developers start working with higher-order functions like sorted(), max(), or filter(). They have a list of data—usually tuples or dictionaries—and they want to target a specific piece of that data to determine the sort order or the maximum value.

The "Key" that isn't a function

# I want to find the tuple with the highest score (the second element)
players = [("Alice", 88), ("Bob", 95), ("Charlie", 91)]

# This is where the learner usually trips up:
top_player = max(players, key=players[1]) 
# TypeError: 'int' object is not callable

If you've run into this, you're likely thinking: "I told Python to look at index 1, why is it complaining that an integer isn't callable?" The issue is that the key argument in max() (and sorted()) doesn't want a value; it wants a function. It needs a set of instructions it can apply to every single item in the list to decide how to compare them.

Most people solve this with a lambda: key=lambda x: x[1]. That works perfectly fine. But as your projects grow, you'll find yourself writing those tiny, one-line lambdas everywhere. It's repetitive, and believe it or not, it's actually slower because Python has to execute a full function call in the bytecode for every single element.

Replacing lambdas with itemgetter

This is where the operator module comes in. It provides a set of efficient, C-implemented functions that do exactly what those lambdas do, but faster and with cleaner syntax. Specifically, operator.itemgetter creates a function for you.

import operator

players = [("Alice", 88), ("Bob", 95), ("Charlie", 91)]

# itemgetter(1) returns a function that fetches the element at index 1
top_player = max(players, key=operator.itemgetter(1))
print(top_player) # ('Bob', 95)

I prefer itemgetter because it's explicit. When I see it in a code review, I immediately know we are extracting a field. Plus, it's incredibly powerful for multi-level sorting. If you want to sort players by score, and then by name if there is a tie, you just pass multiple arguments:

# Sort by score (index 1), then name (index 0)
sorted_players = sorted(players, key=operator.itemgetter(1, 0))

Handling objects with attrgetter

You aren't limited to tuples or lists. If you're dealing with a list of class instances (objects) and you want to sort by an attribute, using lambda x: x.attribute is common, but operator.attrgetter is the professional way to handle it.

from operator import attrgetter

class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

users = [User("Zoe", "zoe@email.com"), User("Alex", "alex@email.com")]

# Sort users by their name attribute
users.sort(key=attrgetter("name"))

Functional arithmetic

While itemgetter and attrgetter are the stars of the show, the operator module also provides functional versions of all the standard Python operators. You might wonder why you'd want operator.add(a, b) when you can just write a + b.

The answer is: passing operations as arguments. If you're using functools.reduce or a similar tool that expects a function, you can't pass the + symbol. You have to pass a function object. Using operator.add is significantly faster than writing lambda x, y: x + y.




📋 Practical Task

Building a Multi-Criteria Employee Directory Sorter

You have a list of employee records. Each record is a dictionary containing the employee's name, department, and years_experience.

Your goal is to sort this list using the operator module. The sorting criteria must be:

  1. Primary sort: Department (Alphabetically)
  2. Secondary sort: Years of Experience (Descending)

Constraints:

  • You must use operator.itemgetter for the department sort.
  • Since itemgetter doesn't support descending order for a single field within a multi-key sort, you should perform the experience sort first (descending), and then the department sort (ascending). Remember that Python's sort() is stable, meaning it preserves the relative order of elements that compare equal.
employees = [
    {"name": "Alice", "dept": "Engineering", "exp": 5},
    {"name": "Bob", "dept": "Sales", "exp": 8},
    {"name": "Charlie", "dept": "Engineering", "exp": 12},
    {"name": "David", "dept": "Sales", "exp": 3},
    {"name": "Eve", "dept": "Engineering", "exp": 5},
]

# Your code here:
# 1. Sort by 'exp' descending
# 2. Sort by 'dept' ascending using operator.itemgetter
Rating
0 0

There are no comments for now.

to be the first to leave a comment.