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

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 Newer

3 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))  # True
import 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 42

Common 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

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

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.