Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
184: The operator Module
I've seen this specific mistake dozens of times when developers start working with higher-order functions like sorted(), max(), or filter(). They have a list of data—usually tuples or dictionaries—and they want to target a specific piece of that data to determine the sort order or the maximum value.
The "Key" that isn't a function
# I want to find the tuple with the highest score (the second element)
players = [("Alice", 88), ("Bob", 95), ("Charlie", 91)]
# This is where the learner usually trips up:
top_player = max(players, key=players[1])
# TypeError: 'int' object is not callable
If you've run into this, you're likely thinking: "I told Python to look at index 1, why is it complaining that an integer isn't callable?" The issue is that the key argument in max() (and sorted()) doesn't want a value; it wants a function. It needs a set of instructions it can apply to every single item in the list to decide how to compare them.
Most people solve this with a lambda: key=lambda x: x[1]. That works perfectly fine. But as your projects grow, you'll find yourself writing those tiny, one-line lambdas everywhere. It's repetitive, and believe it or not, it's actually slower because Python has to execute a full function call in the bytecode for every single element.
Replacing lambdas with itemgetter
This is where the operator module comes in. It provides a set of efficient, C-implemented functions that do exactly what those lambdas do, but faster and with cleaner syntax. Specifically, operator.itemgetter creates a function for you.
import operator
players = [("Alice", 88), ("Bob", 95), ("Charlie", 91)]
# itemgetter(1) returns a function that fetches the element at index 1
top_player = max(players, key=operator.itemgetter(1))
print(top_player) # ('Bob', 95)
I prefer itemgetter because it's explicit. When I see it in a code review, I immediately know we are extracting a field. Plus, it's incredibly powerful for multi-level sorting. If you want to sort players by score, and then by name if there is a tie, you just pass multiple arguments:
# Sort by score (index 1), then name (index 0)
sorted_players = sorted(players, key=operator.itemgetter(1, 0))
Handling objects with attrgetter
You aren't limited to tuples or lists. If you're dealing with a list of class instances (objects) and you want to sort by an attribute, using lambda x: x.attribute is common, but operator.attrgetter is the professional way to handle it.
from operator import attrgetter
class User:
def __init__(self, name, email):
self.name = name
self.email = email
users = [User("Zoe", "zoe@email.com"), User("Alex", "alex@email.com")]
# Sort users by their name attribute
users.sort(key=attrgetter("name"))
Functional arithmetic
While itemgetter and attrgetter are the stars of the show, the operator module also provides functional versions of all the standard Python operators. You might wonder why you'd want operator.add(a, b) when you can just write a + b.
The answer is: passing operations as arguments. If you're using functools.reduce or a similar tool that expects a function, you can't pass the + symbol. You have to pass a function object. Using operator.add is significantly faster than writing lambda x, y: x + y.
📋 Practical Task
Building a Multi-Criteria Employee Directory Sorter
You have a list of employee records. Each record is a dictionary containing the employee's name, department, and years_experience.
Your goal is to sort this list using the operator module. The sorting criteria must be:
- Primary sort: Department (Alphabetically)
- Secondary sort: Years of Experience (Descending)
Constraints:
- You must use
operator.itemgetterfor the department sort. - Since
itemgetterdoesn't support descending order for a single field within a multi-key sort, you should perform the experience sort first (descending), and then the department sort (ascending). Remember that Python'ssort()is stable, meaning it preserves the relative order of elements that compare equal.
employees = [
{"name": "Alice", "dept": "Engineering", "exp": 5},
{"name": "Bob", "dept": "Sales", "exp": 8},
{"name": "Charlie", "dept": "Engineering", "exp": 12},
{"name": "David", "dept": "Sales", "exp": 3},
{"name": "Eve", "dept": "Engineering", "exp": 5},
]
# Your code here:
# 1. Sort by 'exp' descending
# 2. Sort by 'dept' ascending using operator.itemgetter
There are no comments for now.