The operator Module
Reviewed & published by Brayan K
The operator module turns Python's operators and lookups into plain, reusable functions, so you can pass things like "add", "get item 1", or "call .upper()" anywhere a function is expected.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
It's the secret behind clean sort keys and fast reductions: itemgetter, attrgetter, and methodcaller replace fiddly lambdas with faster, more readable building blocks.
What You'll Learn in This Lesson
- itemgetter for clean, fast sort keys
- Sorting by multiple fields at once
- attrgetter for sorting objects by attribute
- methodcaller to call a method on each item
- operator.add / mul as functions for reduce
- Why operator beats lambdas for speed & clarity
1 itemgetter — Clean Sort Keys
itemgetter(i) returns a function that does obj[i]. That's exactly the shape sorted() wants for its key, so sorting a list of tuples or dict items becomes a one-liner that reads like English:
from operator import itemgetter
people = [("Ada", 36), ("Ben", 28), ("Cleo", 41)]
# Sort by age (element 1)
print(sorted(people, key=itemgetter(1)))
# [('Ben', 28), ('Ada', 36), ('Cleo', 41)]
# Sort by name (element 0)
print(sorted(people, key=itemgetter(0)))
# [('Ada', 36), ('Ben', 28), ('Cleo', 41)]
# Sort dict items by value
inventory = {"apple": 3, "banana": 1, "cherry": 7}
print(sorted(inventory.items(), key=itemgetter(1)))
# [('banana', 1), ('apple', 3), ('cherry', 7)]from operator import itemgetter
# (name, department, salary)
staff = [
("Ada", "Eng", 95),
("Ben", "Eng", 80),
("Cleo", "Sales", 80),
]
# Sort by department, then by salary
ordered = sorted(staff, key=itemgetter(1, 2))
for row in ordered:
print(row)
# ✅ Expected output:
# ('Ben', 'Eng', 80)
# ('Ada', 'Eng', 95)
# ('Cleo', 'Sales', 80)2 attrgetter & methodcaller
When you work with objects instead of tuples, use attrgetter('field') to read an attribute. And methodcaller('name', args...) builds a function that calls a method on each item — ideal inside map():
from operator import attrgetter, methodcaller
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
dogs = [Dog("Rex", 5), Dog("Fido", 2), Dog("Spot", 8)]
# Sort objects by the .age attribute
youngest = sorted(dogs, key=attrgetter("age"))
print([d.name for d in youngest]) # ['Fido', 'Rex', 'Spot']
# methodcaller calls a method on each element
words = [" Hello ", "World ", " Python"]
print(list(map(methodcaller("strip"), words)))
# ['Hello', 'World', 'Python']
# It can pass arguments too
print(list(map(methodcaller("replace", "o", "0"), ["foo", "bar"])))
# ['f00', 'bar']Think of it as matching the access style: itemgetter for [ ], attrgetter for .attr, and methodcaller for .method().
from operator import attrgetter
class Book:
def __init__(self, title, year):
self.title = title
self.year = year
books = [
Book("Newer", 2020),
Book("Oldest", 1999),
Book("Middle", 2010),
]
for b in sorted(books, key=attrgetter("year")):
print(b.year, b.title)
# ✅ Expected output:
# 1999 Oldest
# 2010 Middle
# 2020 Newer3 Operators as Functions (with reduce)
Every operator has a function form: operator.add, operator.mul, operator.gt, operator.contains, and so on. These shine when a function needs a binary operation as an argument — most famously functools.reduce:
import operator
from functools import reduce
nums = [1, 2, 3, 4, 5]
# Fold + across the list -> a sum
print(reduce(operator.add, nums)) # 15
# Fold * across the list -> a product
print(reduce(operator.mul, nums)) # 120
# The functions also work standalone
print(operator.add(3, 4)) # 7
print(operator.gt(5, 2)) # True
print(operator.contains([1, 2, 3], 2)) # Trueimport operator
from functools import reduce
# Product of a list (no built-in for this)
factors = [2, 3, 5, 7]
print("product:", reduce(operator.mul, factors))
# operator functions as standalone callables
print("add:", operator.add(10, 5))
print("sub:", operator.sub(10, 5))
print("pow:", operator.pow(2, 8))
# ✅ Expected output:
# product: 210
# add: 15
# sub: 5
# pow: 256🎯 YOUR TURN: Fill in the Blanks
Replace each ___ with the right helper from operator so the leaderboard sorts by score (highest first).
from operator import ___
# (player, score)
scores = [("Ada", 42), ("Ben", 91), ("Cleo", 67)]
# Sort by score (element 1), highest first
ranked = sorted(scores, key=___(1), reverse=True)
for name, pts in ranked:
print(name, pts)
# Expected output:
# Ben 91
# Cleo 67
# Ada 42Common Errors
❌ Calling itemgetter on the whole list instead of passing it as a key
# Wrong: this indexes the list, not each row
sorted(rows, key=itemgetter(rows)) # TypeError✅ Pass the index; sorted applies the getter to each item
from operator import itemgetter
rows = [(3, "c"), (1, "a"), (2, "b")]
print(sorted(rows, key=itemgetter(0))) # [(1, 'a'), (2, 'b'), (3, 'c')]❌ Using attrgetter on a dict (dicts use keys, not attributes)
row = {"age": 30}
attrgetter("age")(row) # AttributeError: 'dict' object has no attribute 'age'✅ Use itemgetter for dict keys
from operator import itemgetter
row = {"age": 30}
print(itemgetter("age")(row)) # 30❌ Forgetting methodcaller returns a callable, not a result
upper = methodcaller("upper")
print(upper) # <operator.methodcaller object ...> (you must CALL it)✅ Apply it to a value (or via map)
from operator import methodcaller
upper = methodcaller("upper")
print(upper("hello")) # HELLO🎯 Mini Challenge: Sales Report
Sort a list of sales records by region then revenue (highest first within a region), and compute the grand total with reduce and operator.add.
from operator import itemgetter, add
from functools import reduce
# (rep, region, revenue)
sales = [
("Ada", "West", 300),
("Ben", "East", 500),
("Cleo", "West", 450),
("Dan", "East", 200),
]
# Sort by region (asc), then revenue (desc)
ordered = sorted(sales, key=itemgetter(2), reverse=True)
ordered = sorted(ordered, key=itemgetter(1))
for row in ordered:
print(row)
total = reduce(add, map(itemgetter(2), sales))
print("Total:", total)
# ✅ Expected output:
# ('Ben', 'East', 500)
# ('Dan', 'East', 200)
# ('Cleo', 'West', 450)
# ('Ada', 'West', 300)
# Total: 1450📚 Keep Learning
- operator — Standard operators as functions (official docs)
- sorted() and the key argument
- functools.reduce — folding a function across a sequence
Frequently Asked Questions
Lesson complete — your sort keys are pristine!
You can reach for itemgetter to sort tuples and dict items, attrgetter to sort objects, methodcaller to call a method on every element, and operator functions like add and mul to power reduce — all faster and clearer than lambdas.
Practice quiz
What does itemgetter(1) return when used as a callable?
- The value 1
- A list of all second elements
- A function that returns obj[1] for whatever it's given
- obj.attr_1
Answer: A function that returns obj[1] for whatever it's given. itemgetter(1) builds a function that does obj[1], ideal as a sort key.
What is sorted(people, key=itemgetter(1)) for people = [('Ada',36),('Ben',28),('Cleo',41)]?
- [('Ben', 28), ('Ada', 36), ('Cleo', 41)]
- [('Cleo', 41), ('Ada', 36), ('Ben', 28)]
- [('Ada', 36), ('Ben', 28), ('Cleo', 41)]
- [('Ada', 36), ('Cleo', 41), ('Ben', 28)]
Answer: [('Ben', 28), ('Ada', 36), ('Cleo', 41)]. It sorts by element 1 (age) ascending: 28, 36, 41.
How do you sort by element 1, then break ties using element 0?
- itemgetter(1)(0)
- itemgetter([1, 0])
- itemgetter(1) + itemgetter(0)
- itemgetter(1, 0)
Answer: itemgetter(1, 0). Passing several indexes, itemgetter(1, 0), returns a tuple key sorting by 1 then 0.
Which helper reads an attribute, e.g. to sort objects by their .age?
- itemgetter('age')
- attrgetter('age')
- methodcaller('age')
- getattr_sorted('age')
Answer: attrgetter('age'). attrgetter('age') builds a function that does obj.age, matching attribute access.
What does methodcaller('strip') do when mapped over strings?
- Calls .strip() on each string, returning the stripped results
- Returns the strip method object only
- Sorts the strings
- Raises an error because strip needs arguments
Answer: Calls .strip() on each string, returning the stripped results. methodcaller('strip') builds a function that calls .strip() on each element it receives.
What is reduce(operator.mul, [1, 2, 3, 4, 5])?
- 15
- 25
- 120
- 5
Answer: 120. It folds multiplication across the list: 1*2*3*4*5 = 120.
Which call matches the three access styles correctly?
- itemgetter for .attr, attrgetter for [k], methodcaller for .m()
- itemgetter for [k], attrgetter for .attr, methodcaller for .m()
- itemgetter for .m(), attrgetter for [k], methodcaller for .attr
- They are interchangeable on any object
Answer: itemgetter for [k], attrgetter for .attr, methodcaller for .m(). itemgetter does obj[k], attrgetter does obj.attr, and methodcaller does obj.m(args).
Why does attrgetter('age') fail on a plain dict like {'age': 30}?
- Dicts are immutable
- attrgetter requires two arguments
- It actually works fine
- Dicts use keys (indexing), not attributes, so itemgetter('age') is needed
Answer: Dicts use keys (indexing), not attributes, so itemgetter('age') is needed. A dict has no .age attribute; use itemgetter('age') which does dict['age'].
What does operator.contains([1, 2, 3], 2) return?
- False
- True
- 2
- [2]
Answer: True. operator.contains is the function form of 'in', and 2 is in the list, so it returns True.
When is passing operator.add more useful than writing + directly?
- Never; + is always required
- Only for string concatenation
- When a function needs a binary operation as an argument, e.g. reduce(operator.add, nums)
- When adding exactly two literals
Answer: When a function needs a binary operation as an argument, e.g. reduce(operator.add, nums). You can't pass + as an argument, but operator.add is a callable you can hand to reduce, map, etc.
Continue this course
- Previous: The statistics Module
- Next: Binary Data with struct — Pack and unpack C-style binary data and read file headers
- Quick reference: Python cheat sheet
Frequently asked questions
What is the operator module for?
The operator module provides ordinary functions that do the same thing as Python's built-in operators and lookups — operator.add(a, b) is a + b, operator.itemgetter(1) pulls out element 1. It lets you pass an operator around as a value, which is exactly what functions like sorted(), map(), and reduce() need for their key and function arguments.
Why use itemgetter instead of a lambda?
itemgetter is faster and clearer. sorted(rows, key=itemgetter(1)) reads as 'sort by column 1' and runs in C, while key=lambda r: r[1] creates a Python-level function that's slower and noisier. itemgetter can also grab several fields at once — itemgetter(0, 2) — to sort by multiple keys, which a lambda makes clumsy.
What's the difference between itemgetter, attrgetter, and methodcaller?
They cover the three ways you access things in Python. itemgetter(k) does obj[k] (indexing/keys), attrgetter('x') does obj.x (attributes), and methodcaller('m', args) does obj.m(args) (calling a method). Pick the one that matches how you'd reach the value by hand.
When is operator.add useful versus just writing +?
Inside other functions. You can't pass + as an argument, but you can pass operator.add. reduce(operator.add, numbers) sums a list, and it's the standard way to fold a binary operation across a sequence. For everyday code you'd still write a + b directly.