The operator module provides function equivalents of Python operators. Faster and cleaner than lambdas for common operations.
itemgetter: Access by Index or Key
from operator import itemgetter
# Get item by index
get_first = itemgetter(0)
print(get_first([1, 2, 3])) # 1
# Get multiple items
get_ends = itemgetter(0, -1)
print(get_ends([1, 2, 3, 4, 5])) # (1, 5)
# Get dict value
get_name = itemgetter('name')
print(get_name({'name': 'Alice', 'age': 30})) # AliceSorting with itemgetter
from operator import itemgetter
users = [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25},
{'name': 'Carol', 'age': 35},
]
# Sort by key
sorted_by_age = sorted(users, key=itemgetter('age'))
# Sort by multiple keys
data = [('Alice', 'B'), ('Bob', 'A'), ('Alice', 'A')]
sorted_data = sorted(data, key=itemgetter(0, 1))
# [('Alice', 'A'), ('Alice', 'B'), ('Bob', 'A')]attrgetter: Access Attributes
from operator import attrgetter
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
users = [User('Alice', 30), User('Bob', 25), User('Carol', 35)]
# Sort by attribute
sorted_users = sorted(users, key=attrgetter('age'))
# Get attribute value
get_name = attrgetter('name')
names = [get_name(u) for u in users] # ['Alice', 'Bob', 'Carol']
# Multiple attributes
get_info = attrgetter('name', 'age')
print(get_info(users[0])) # ('Alice', 30)Nested Attributes
from operator import attrgetter
class Address:
def __init__(self, city):
self.city = city
class Person:
def __init__(self, name, address):
self.name = name
self.address = address
person = Person('Alice', Address('NYC'))
# Access nested attribute
get_city = attrgetter('address.city')
print(get_city(person)) # NYCmethodcaller: Call Methods
from operator import methodcaller
# Call method with no args
upper = methodcaller('upper')
print(upper('hello')) # HELLO
# Call method with args
split_comma = methodcaller('split', ',')
print(split_comma('a,b,c')) # ['a', 'b', 'c']
# Call method with kwargs
format_num = methodcaller('format', '.2f')
print(format_num(3.14159)) # Error - format() doesn't work this way
# Practical use
strip_lower = methodcaller('strip')
words = [' hello ', ' world ']
cleaned = list(map(strip_lower, words)) # ['hello', 'world']Operator Functions
Replace operators with functions:
from operator import add, sub, mul, truediv, mod, pow
from operator import eq, ne, lt, le, gt, ge
from operator import and_, or_, not_
from operator import neg, pos, abs as abs_
# Arithmetic
add(2, 3) # 5
mul(4, 5) # 20
truediv(10, 3) # 3.333...
pow(2, 8) # 256
# Comparison
lt(1, 2) # True
eq(5, 5) # True
# Boolean
and_(True, False) # False
not_(True) # False
# With reduce
from functools import reduce
reduce(add, [1, 2, 3, 4, 5]) # 15
reduce(mul, [1, 2, 3, 4, 5]) # 120Container Operations
from operator import contains, countOf, indexOf
from operator import getitem, setitem, delitem
# contains
contains([1, 2, 3], 2) # True (same as 2 in [1, 2, 3])
# countOf
countOf([1, 2, 2, 3, 2], 2) # 3
# indexOf
indexOf([1, 2, 3], 2) # 1
# Item access
data = [1, 2, 3]
getitem(data, 1) # 2
setitem(data, 1, 99) # data is now [1, 99, 3]Why operator Over lambdas?
from operator import itemgetter, attrgetter
# Lambda: slower, less readable
sorted(users, key=lambda x: x['age'])
sorted(users, key=lambda x: x.name)
# operator: faster, cleaner
sorted(users, key=itemgetter('age'))
sorted(users, key=attrgetter('name'))Performance: itemgetter and attrgetter are implemented in C, making them faster than equivalent lambdas.
Practical Examples
Finding Max by Attribute
from operator import attrgetter
@dataclass
class Product:
name: str
price: float
products = [
Product('Apple', 1.50),
Product('Banana', 0.75),
Product('Cherry', 3.00),
]
most_expensive = max(products, key=attrgetter('price'))
# Product(name='Cherry', price=3.0)Grouping by Key
from operator import itemgetter
from itertools import groupby
data = [
('fruit', 'apple'),
('fruit', 'banana'),
('veggie', 'carrot'),
('fruit', 'cherry'),
('veggie', 'daikon'),
]
# Sort then group
data.sort(key=itemgetter(0))
for category, items in groupby(data, key=itemgetter(0)):
print(f"{category}: {list(items)}")Extracting Columns
from operator import itemgetter
rows = [
('Alice', 30, 'NYC'),
('Bob', 25, 'LA'),
('Carol', 35, 'Chicago'),
]
# Extract name and city columns
extract = itemgetter(0, 2)
extracted = [extract(row) for row in rows]
# [('Alice', 'NYC'), ('Bob', 'LA'), ('Carol', 'Chicago')]Chaining Method Calls
from operator import methodcaller
# Process strings
strip = methodcaller('strip')
lower = methodcaller('lower')
def clean(s):
return lower(strip(s))
data = [' Hello ', ' WORLD ', ' Python ']
cleaned = [clean(s) for s in data]
# ['hello', 'world', 'python']Quick Reference
from operator import (
# Getters
itemgetter, # obj[key]
attrgetter, # obj.attr
methodcaller, # obj.method(*args)
# Arithmetic
add, sub, mul, truediv, floordiv, mod, pow,
neg, pos, abs,
# Comparison
eq, ne, lt, le, gt, ge,
# Logical
and_, or_, not_,
# Container
contains, countOf, indexOf,
getitem, setitem, delitem,
)| Function | Equivalent |
|---|---|
itemgetter(k) | lambda x: x[k] |
attrgetter(a) | lambda x: x.a |
methodcaller(m) | lambda x: x.m() |
add(a, b) | a + b |
contains(a, b) | b in a |
Use operator when you need a function for what would normally be an operator or simple attribute access.
React to this post: