operator Module¶
The operator module provides function equivalents for Python's built-in operators. These are faster than lambdas and cleaner for functional programming.
import operator
# or
from operator import itemgetter, attrgetter, methodcaller
Why Use operator?¶
from operator import add, mul
# Lambda (slower, verbose)
result = reduce(lambda x, y: x + y, numbers)
# operator (faster, cleaner)
result = reduce(add, numbers)
Benefits: - Faster: Implemented in C - Cleaner: More readable than lambdas - Documented: Clear intent from function name
itemgetter¶
Retrieve items by index or key. Returns a callable.
Single Item¶
from operator import itemgetter
# Get item at index 1
get_second = itemgetter(1)
print(get_second([10, 20, 30])) # 20
print(get_second("hello")) # 'e'
print(get_second({'a': 1, 'b': 2, 1: 'x'})) # 'x'
Multiple Items¶
from operator import itemgetter
# Get multiple items
get_first_and_third = itemgetter(0, 2)
print(get_first_and_third([10, 20, 30, 40])) # (10, 30)
print(get_first_and_third("hello")) # ('h', 'l')
Sorting with itemgetter¶
from operator import itemgetter
# Sort list of tuples by second element
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
sorted(pairs, key=itemgetter(1))
# [(3, 'a'), (1, 'b'), (2, 'c')]
# Sort by multiple keys
data = [(1, 'b', 30), (2, 'a', 20), (1, 'a', 10)]
sorted(data, key=itemgetter(0, 1))
# [(1, 'a', 10), (1, 'b', 30), (2, 'a', 20)]
With Dictionaries¶
from operator import itemgetter
records = [
{'name': 'Alice', 'age': 30, 'score': 85},
{'name': 'Bob', 'age': 25, 'score': 92},
{'name': 'Charlie', 'age': 35, 'score': 78},
]
# Sort by score
sorted(records, key=itemgetter('score'))
# [{'name': 'Charlie'...}, {'name': 'Alice'...}, {'name': 'Bob'...}]
# Get specific fields
get_name_and_score = itemgetter('name', 'score')
[get_name_and_score(r) for r in records]
# [('Alice', 85), ('Bob', 92), ('Charlie', 78)]
attrgetter¶
Retrieve attributes from objects. Returns a callable.
Single Attribute¶
from operator import attrgetter
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
people = [
Person('Alice', 30),
Person('Bob', 25),
Person('Charlie', 35),
]
# Sort by age
get_age = attrgetter('age')
sorted(people, key=get_age)
# [Bob(25), Alice(30), Charlie(35)]
# Equivalent lambda (slower)
sorted(people, key=lambda p: p.age)
Multiple Attributes¶
from operator import attrgetter
# Get multiple attributes
get_name_and_age = attrgetter('name', 'age')
for person in people:
print(get_name_and_age(person))
# ('Alice', 30)
# ('Bob', 25)
# ('Charlie', 35)
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
people = [
Person('Alice', Address('NYC')),
Person('Bob', Address('LA')),
]
# Access nested attribute
get_city = attrgetter('address.city')
[get_city(p) for p in people]
# ['NYC', 'LA']
# Equivalent lambda
[p.address.city for p in people]
Sorting by Multiple Attributes¶
from operator import attrgetter
class Student:
def __init__(self, name, grade, age):
self.name = name
self.grade = grade
self.age = age
students = [
Student('Alice', 85, 20),
Student('Bob', 92, 19),
Student('Charlie', 85, 21),
]
# Sort by grade, then by age
sorted(students, key=attrgetter('grade', 'age'))
# [Alice(85, 20), Charlie(85, 21), Bob(92, 19)]
methodcaller¶
Call a method with specified arguments. Returns a callable.
Basic Usage¶
from operator import methodcaller
# Create a method caller
upper = methodcaller('upper')
strip_x = methodcaller('strip', 'x')
print(upper('hello')) # 'HELLO'
print(strip_x('xxhelloxx')) # 'hello'
With Collections¶
from operator import methodcaller
strings = [' hello ', ' world ', ' python ']
# Strip all strings
list(map(methodcaller('strip'), strings))
# ['hello', 'world', 'python']
# Split all strings
sentences = ['a b c', 'x y z']
list(map(methodcaller('split'), sentences))
# [['a', 'b', 'c'], ['x', 'y', 'z']]
Sorting with Methods¶
from operator import methodcaller
# Sort strings by lowercase
words = ['Banana', 'apple', 'Cherry']
sorted(words, key=methodcaller('lower'))
# ['apple', 'Banana', 'Cherry']
# Sort by custom method
class Task:
def __init__(self, name, priority):
self.name = name
self.priority = priority
def get_sort_key(self):
return (-self.priority, self.name)
tasks = [Task('A', 1), Task('B', 2), Task('C', 1)]
sorted(tasks, key=methodcaller('get_sort_key'))
Arithmetic Operators¶
from operator import add, sub, mul, truediv, floordiv, mod, pow, neg
add(2, 3) # 5 (2 + 3)
sub(5, 2) # 3 (5 - 2)
mul(3, 4) # 12 (3 * 4)
truediv(7, 2) # 3.5 (7 / 2)
floordiv(7, 2) # 3 (7 // 2)
mod(7, 3) # 1 (7 % 3)
pow(2, 3) # 8 (2 ** 3)
neg(5) # -5 (-5)
With reduce¶
from functools import reduce
from operator import add, mul
numbers = [1, 2, 3, 4, 5]
# Sum
reduce(add, numbers) # 15
# Product
reduce(mul, numbers) # 120
Comparison Operators¶
from operator import eq, ne, lt, le, gt, ge
eq(2, 2) # True (2 == 2)
ne(2, 3) # True (2 != 3)
lt(2, 3) # True (2 < 3)
le(2, 2) # True (2 <= 2)
gt(3, 2) # True (3 > 2)
ge(3, 3) # True (3 >= 3)
Filtering with Comparisons¶
from operator import lt
from functools import partial
# Filter values less than 5
is_small = partial(lt, 5) # Note: lt(5, x) means 5 < x
# This is actually "is greater than 5"!
# For "less than 5", use:
from operator import gt
is_less_than_5 = partial(gt, 5) # gt(5, x) means 5 > x
numbers = [1, 3, 5, 7, 9]
list(filter(is_less_than_5, numbers)) # [1, 3]
Logical Operators¶
from operator import and_, or_, not_, xor
# Bitwise operations
and_(5, 3) # 1 (0b101 & 0b011 = 0b001)
or_(5, 3) # 7 (0b101 | 0b011 = 0b111)
xor(5, 3) # 6 (0b101 ^ 0b011 = 0b110)
not_(0) # True
# Note: and_, or_ are BITWISE, not logical!
# For logical operations, use: all(), any()
Sequence Operators¶
from operator import concat, contains, countOf, indexOf
concat([1, 2], [3, 4]) # [1, 2, 3, 4]
concat('hello', ' world') # 'hello world'
contains([1, 2, 3], 2) # True
contains('hello', 'ell') # True
countOf([1, 2, 2, 3, 2], 2) # 3
indexOf([1, 2, 3], 2) # 1
In-Place Operators¶
from operator import iadd, isub, imul
# These modify mutable objects in place
lst = [1, 2]
iadd(lst, [3, 4]) # lst is now [1, 2, 3, 4]
# For immutables, they return new objects
x = 5
x = iadd(x, 3) # x is now 8
Practical Examples¶
Extract Multiple Fields¶
from operator import itemgetter
data = [
('Alice', 30, 'NYC', 85),
('Bob', 25, 'LA', 92),
('Charlie', 35, 'SF', 78),
]
# Extract name and score
extract = itemgetter(0, 3)
[extract(row) for row in data]
# [('Alice', 85), ('Bob', 92), ('Charlie', 78)]
Sort Dictionary by Value¶
from operator import itemgetter
scores = {'Alice': 85, 'Bob': 92, 'Charlie': 78}
# Sort by value (ascending)
sorted(scores.items(), key=itemgetter(1))
# [('Charlie', 78), ('Alice', 85), ('Bob', 92)]
# Sort by value (descending)
sorted(scores.items(), key=itemgetter(1), reverse=True)
# [('Bob', 92), ('Alice', 85), ('Charlie', 78)]
Group and Sort Objects¶
from operator import attrgetter
from itertools import groupby
class Task:
def __init__(self, category, priority, name):
self.category = category
self.priority = priority
self.name = name
tasks = [
Task('work', 1, 'Email'),
Task('home', 2, 'Laundry'),
Task('work', 2, 'Meeting'),
Task('home', 1, 'Dishes'),
]
# Sort by category, then priority
tasks.sort(key=attrgetter('category', 'priority'))
# Group by category
for category, group in groupby(tasks, key=attrgetter('category')):
print(f"{category}: {[t.name for t in group]}")
Calculate with reduce¶
from functools import reduce
from operator import mul, add
# Factorial
def factorial(n):
return reduce(mul, range(1, n + 1), 1)
print(factorial(5)) # 120
# Dot product
def dot_product(v1, v2):
return reduce(add, map(mul, v1, v2))
print(dot_product([1, 2, 3], [4, 5, 6])) # 32
Performance Comparison¶
import timeit
from operator import itemgetter, attrgetter
data = [(i, str(i)) for i in range(1000)]
# Lambda vs itemgetter
lambda_time = timeit.timeit(
lambda: sorted(data, key=lambda x: x[1]),
number=1000
)
itemgetter_time = timeit.timeit(
lambda: sorted(data, key=itemgetter(1)),
number=1000
)
print(f"lambda: {lambda_time:.3f}s")
print(f"itemgetter: {itemgetter_time:.3f}s")
# itemgetter is typically 10-20% faster
Summary¶
| Function | Purpose | Example |
|---|---|---|
itemgetter(k) |
Get item by key/index | itemgetter(1)(lst) |
attrgetter(a) |
Get attribute | attrgetter('name')(obj) |
methodcaller(m) |
Call method | methodcaller('upper')(s) |
add, mul, etc. |
Arithmetic | reduce(add, nums) |
eq, lt, etc. |
Comparison | filter(partial(lt, 5), nums) |
Key Takeaways:
itemgetterandattrgetterare faster than lambdas- Use for sorting:
sorted(data, key=itemgetter('field')) - Support multiple keys:
itemgetter(0, 2),attrgetter('a', 'b') attrgettersupports nested attributes:attrgetter('a.b.c')- Arithmetic operators work with
reducefor aggregations - All functions are implemented in C for performance