Placement Prep

Python operator Module: Operators as First-Class Functions

Python's operator module turns every built-in operator into a callable: add, mul, itemgetter, and more. Faster than lambdas in tight loops.

By FACE Prep Team 6 min read
python operator-module functools placement-prep functional-programming python-stdlib

Python’s operator module gives every built-in operator a proper function name, so you can pass it to map, sorted, or functools.reduce without wrapping it in a lambda.

What the operator Module Solves

Higher-order functions like functools.reduce and sorted take a callable as an argument. If you want to sum a list with reduce, one option is:

import functools
result = functools.reduce(lambda x, y: x + y, [10, 20, 30])

The lambda works, but it adds a Python-level function call on every iteration. The operator module offers a direct alternative:

import functools
import operator

result = functools.reduce(operator.add, [10, 20, 30])
print(result)  # 60

operator.add is a C-level callable. No lambda, no extra frame creation, no extra name lookup per call. The difference shows up in profile measurements when the list is large or the computation runs in a tight inner loop.

The full module is part of Python’s standard library, per the Python 3 operator module documentation. No installation needed; a single import is enough:

import operator

Using from operator import * works but imports roughly 60 names into the local namespace. Explicit imports are cleaner for production code and placement submissions alike.

Arithmetic and Comparison Functions

Every Python arithmetic operator has a corresponding operator module function. The comparison operators follow the same pattern.

Arithmetic Functions

FunctionEquivalentExampleResult
operator.add(a, b)a + boperator.add(40, 20)60
operator.sub(a, b)a - boperator.sub(40, 20)20
operator.mul(a, b)a * boperator.mul(40, 20)800
operator.truediv(a, b)a / boperator.truediv(40, 20)2.0
operator.floordiv(a, b)a // boperator.floordiv(40, 20)2
operator.mod(a, b)a % boperator.mod(10, 3)1
operator.pow(a, b)a ** boperator.pow(2, 10)1024
import operator

a, b = 40, 20
print(operator.add(a, b))       # 60
print(operator.sub(a, b))       # 20
print(operator.mul(a, b))       # 800
print(operator.truediv(a, b))   # 2.0
print(operator.floordiv(a, b))  # 2
print(operator.mod(10, 3))      # 1
print(operator.pow(2, 10))      # 1024

operator.truediv mirrors Python 3’s / operator and always returns a float. The calculator program in Python covers how the / vs // distinction matters in placement coding tests.

Comparison Functions

FunctionEquivalentExampleResult
operator.lt(a, b)a < boperator.lt(3, 5)True
operator.le(a, b)a <= boperator.le(5, 5)True
operator.gt(a, b)a > boperator.gt(5, 3)True
operator.ge(a, b)a >= boperator.ge(5, 5)True
operator.eq(a, b)a == boperator.eq(5, 5)True
operator.ne(a, b)a != boperator.ne(5, 3)True

These six comparison functions become useful when sorting or filtering logic needs to be parameterised at runtime. Instead of hard-coding a comparison symbol in a condition, pass operator.lt or operator.gt as a callable argument.

Logical and Bitwise Functions

One naming detail: operator.and_ and operator.or_ carry a trailing `_` because and and or are reserved keywords in Python. The `_` suffix avoids a name collision without changing the operation’s meaning.

FunctionEquivalentExampleResult
operator.and_(a, b)a & boperator.and_(3, 4)0
operator.or_(a, b)`ab`operator.or_(3, 4)
operator.xor(a, b)a ^ boperator.xor(3, 4)7
operator.invert(a)~aoperator.invert(3)-4
operator.not_(a)not aoperator.not_(True)False
import operator

print(operator.and_(3, 4))   # 0   (0b011 & 0b100 = 0b000)
print(operator.or_(3, 4))    # 7   (0b011 | 0b100 = 0b111)
print(operator.xor(3, 4))    # 7   (0b011 ^ 0b100 = 0b111)
print(operator.invert(3))    # -4  (~3 in two's complement)
print(operator.not_(True))   # False

operator.not_ applies logical NOT and returns True or False. operator.invert applies bitwise NOT and flips every bit of the integer. They are not interchangeable: operator.not_(3) returns False (because 3 is truthy), while operator.invert(3) returns -4.

The same trailing `_` pattern appears in operator.not_ for the same reason: not is a keyword, so the function appends `_` to avoid the clash.

Item and Attribute Access: itemgetter, attrgetter, methodcaller

Three functions in the operator module are particularly useful for sorting and data extraction. Each returns a callable object, not a value.

operator.itemgetter

operator.itemgetter(key) returns a function that retrieves obj[key] from any subscriptable object. Pass a single key, multiple keys, or an integer index.

import operator

students = [
    {'name': 'Arjun', 'gpa': 8.4, 'year': 3},
    {'name': 'Meera', 'gpa': 9.1, 'year': 2},
    {'name': 'Kiran', 'gpa': 8.9, 'year': 3},
]

ranked = sorted(students, key=operator.itemgetter('gpa'), reverse=True)
for s in ranked:
    print(s['name'], s['gpa'])
# Meera 9.1
# Kiran 8.9
# Arjun 8.4

Passing multiple arguments to itemgetter produces a multi-key sort. The result sorts by the first key first, then by the second key within ties.

# Sort by year first, then gpa within the same year
by_year_gpa = sorted(students, key=operator.itemgetter('year', 'gpa'))

The equivalent lambda for the single-key case is lambda s: s['gpa']. The itemgetter form is slightly faster in tight loops because no Python frame is built per call.

operator.attrgetter

operator.attrgetter('attr') returns a function that retrieves obj.attr from any object. Dotted paths navigate nested attributes in one call.

import operator
from dataclasses import dataclass

@dataclass
class Student:
    name: str
    gpa: float

roster = [Student('Arjun', 8.4), Student('Meera', 9.1), Student('Kiran', 8.9)]

get_gpa = operator.attrgetter('gpa')
ranked = sorted(roster, key=get_gpa, reverse=True)
print([s.name for s in ranked])  # ['Meera', 'Kiran', 'Arjun']

operator.attrgetter('address.city') handles two-level attribute access in one call, with no intermediate lambda needed.

operator.methodcaller

operator.methodcaller('method', *args) returns a callable that invokes obj.method(*args) on whatever object is passed to it.

import operator

words = ['banana', 'apple', 'cherry']
upper_all = list(map(operator.methodcaller('upper'), words))
print(upper_all)  # ['BANANA', 'APPLE', 'CHERRY']

This is equivalent to [w.upper() for w in words], but when you need to pass a method call into map or filter, methodcaller avoids writing lambda x: x.upper() repeatedly.

Real-World Patterns: reduce, sorted, and accumulate

Sum and Product with functools.reduce

Per the functools.reduce documentation, reduce(func, iterable) applies func cumulatively to the items in iterable. With operator functions, two common reductions become one-liners:

import functools
import operator

nums = [1, 2, 3, 4, 5]

total = functools.reduce(operator.add, nums)
print(total)    # 15

product = functools.reduce(operator.mul, nums)
print(product)  # 120

functools.reduce(operator.mul, range(1, n+1)) computes the factorial of n. For n=5, the call evaluates 1*2*3*4*5 and returns 120. This is a common functional-programming pattern in placement interview questions.

The sum of array elements in Python guide covers the loop-based approach to accumulating a sum. functools.reduce(operator.add, arr) is the one-liner equivalent of that loop.

Running Totals with itertools.accumulate

itertools.accumulate applies a function cumulatively and returns all intermediate results, not just the final value.

import itertools
import operator

nums = [1, 2, 3, 4, 5]

running_products = list(itertools.accumulate(nums, operator.mul))
print(running_products)  # [1, 2, 6, 24, 120]

Each element in the output is the product of all elements up to that position: 1, 1*2, 2*3, 6*4, 24*5. operator.mul here replaces what would otherwise be lambda a, b: a * b.

Multi-Key Sort with itemgetter

Sorting structured data by two criteria at once:

import operator

records = [
    ('Alice', 'CSE', 9.1),
    ('Bob', 'ECE', 8.7),
    ('Carol', 'CSE', 8.9),
    ('Dave', 'ECE', 9.1),
]

by_branch_then_gpa = sorted(records, key=operator.itemgetter(1, 2))
for r in by_branch_then_gpa:
    print(r)
# ('Carol', 'CSE', 8.9)
# ('Alice', 'CSE', 9.1)
# ('Bob', 'ECE', 8.7)
# ('Dave', 'ECE', 9.1)

Index 1 is the branch string, index 2 is the GPA float. The sort groups by branch first (alphabetically), then by GPA ascending within each branch.

For more Python programs that combine sorting and functional patterns, the Python basic programs collection covers around forty worked examples.

Performance: C-Level Functions vs. Lambda

operator module functions are implemented in C as part of CPython. A lambda like lambda x, y: x + y creates a Python function object, and every call to it builds a Python stack frame, resolves the names x and y in the local scope, then returns through Python’s function-call protocol. operator.add skips that entire path and calls directly into C.

The gap is visible when the reduction runs over thousands of elements. In production code processing large datasets, functools.reduce(operator.add, large_list) consistently outperforms functools.reduce(lambda x, y: x + y, large_list) when profiled in CPython. For most placement coding questions, correctness matters more than this gap. In code where tight loops over large sequences appear, the operator form is the right default.


The same tight inner-loop logic that makes functools.reduce(operator.mul, range(1, n+1)) fast also appears in LLM probability-scoring pipelines, where token log-likelihoods are accumulated product-by-product. TinkerLLM is a Python-first environment to build tools like that, starting at ₹299.

Primary sources

Frequently asked questions

What is the difference between operator.add(a, b) and a + b?

Both produce the same result. The key difference is that operator.add is a proper callable object. You can store it in a variable, pass it to another function, or use it as the key argument in sorted — none of which are possible with the + symbol alone.

Why do operator.and_ and operator.or_ have a trailing underscore?

The trailing _ prevents a name collision with Python's built-in keywords and and or. Python reserves those words for boolean short-circuit evaluation. The operator module uses and_ and or_ for the bitwise versions of those operations.

When should I use operator.itemgetter instead of a lambda?

Use operator.itemgetter when sorting or filtering by one or more dictionary keys or sequence positions. It is more readable than lambda x: x['key'] and runs slightly faster because it is implemented in C.

Can operator.mul compute factorials with functools.reduce?

Yes. functools.reduce(operator.mul, range(1, n+1)) computes n factorial. For n=5, reduce multiplies 1*2*3*4*5 and returns 120. This is a common functional-programming pattern in Python placement interviews.

What does operator.methodcaller do?

operator.methodcaller('method_name', *args) returns a callable that invokes the named method on whatever object you pass to it. For example, operator.methodcaller('upper') applied to 'hello' returns 'HELLO'. Useful when applying the same method across many objects in a list.

Are operator module functions faster than lambda functions in Python?

Yes in practice, especially in tight loops. operator module functions are implemented in C and avoid the Python-level frame setup that a lambda creates. The difference is most visible in functools.reduce or map calls over large sequences.

Build AI projects

A self-paced playground for building with LLMs.

TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.

Try TinkerLLM (₹299 launch)
Free AI Roadmap PDF