Python

attrgetter vs itemgetter: Cleaner Data Access in Python

Learn the difference between operator.itemgetter and operator.attrgetter, when to use each for sorting and accessing data, and how they perform compared to lambdas.

August 2026 6 min read 13 views 0 hearts

Python's attrgetter vs itemgetter: When to Use Each for Cleaner Data Access

You're working with a list of dictionaries representing employees, and you need to sort them by salary. You could write a lambda, but there's a cleaner way. Python's operator module gives us two powerful tools: itemgetter and attrgetter. They look similar, but they solve different problems.

Let me break down exactly when and why you'd choose one over the other.

The Core Difference

itemgetter works on sequences and mappings (lists, tuples, dictionaries). attrgetter works on objects with attributes.

Here's the simplest way to think about it:

  • Use itemgetter when you access data with square brackets: my_dict['key'] or my_list[0]
  • Use attrgetter when you access data with dot notation: my_object.attribute

itemgetter in Action

When you're dealing with dictionary data, itemgetter is your friend:

from operator import itemgetter

employees = [
    {'name': 'Alice', 'salary': 85000, 'department': 'Engineering'},
    {'name': 'Bob', 'salary': 72000, 'department': 'Marketing'},
    {'name': 'Charlie', 'salary': 95000, 'department': 'Engineering'}
]

# Sort by salary
sorted_employees = sorted(employees, key=itemgetter('salary'))

It also shines with multiple keys:

# Sort by department, then salary
sorted_employees = sorted(employees, key=itemgetter('department', 'salary'))

And here's where PythonSkillset users often get surprised — itemgetter works on tuples and lists too:

from operator import itemgetter

data = [(3, 'apple'), (1, 'banana'), (2, 'cherry')]
sorted_data = sorted(data, key=itemgetter(0))  # Sorts by first element

attrgetter for Object Attributes

Now imagine you're working with class instances instead of dictionaries:

from operator import attrgetter

class Employee:
    def __init__(self, name, salary, department):
        self.name = name
        self.salary = salary
        self.department = department
    def __repr__(self):
        return f"{self.name} ({self.salary})"

employees = [
    Employee('Alice', 85000, 'Engineering'),
    Employee('Bob', 72000, 'Marketing'),
    Employee('Charlie', 95000, 'Engineering')
]

# Sort by salary attribute
sorted_employees = sorted(employees, key=attrgetter('salary'))

Notice the difference? With attrgetter, you pass the attribute name as a string. With itemgetter, you pass the dictionary key.

The Chained Attributes Trick

Here's something that makes attrgetter especially useful:

# When you have nested objects
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('New York')),
    Person('Bob', Address('Austin')),
    Person('Charlie', Address('Denver'))
]

# Sort by city through the address attribute
sorted_people = sorted(people, key=attrgetter('address.city'))

Try doing that with a lambda without making your code look messy.

Performance Comparison

Both functions are implemented in C, making them faster than lambda in most cases:

from operator import itemgetter, attrgetter
import timeit

# With dictionaries
data = [{'a': i, 'b': i*2} for i in range(1000)]

lambda_time = timeit.timeit(
    'sorted(data, key=lambda x: x["a"])',
    globals={'data': data},
    number=10000
)

itemgetter_time = timeit.timeit(
    'sorted(data, key=itemgetter("a"))',
    globals={'data': data, 'itemgetter': itemgetter},
    number=10000
)

On Python 3.11, itemgetter typically runs about 10-20% faster than an equivalent lambda.

When NOT to Use Them

itemgetter and attrgetter aren't always the right choice. Skip them when:

  1. You need to transform data — If you need abs(x) or string manipulation, lambda is clearer
  2. You're accessing nested dictionary keysitemgetter works on one level. For data['user']['name'], a lambda is simpler
  3. Readability takes a hit — Sometimes a simple lambda is more obvious to your teammates

Real-World PythonSkillset Example

At PythonSkillset.com, we process user submission data regularly. Here's how we use both:

from operator import itemgetter, attrgetter

# itemgetter for raw API responses (dictionaries)
api_users = [
    {'username': 'python_dev', 'score': 87, 'articles': 12},
    {'username': 'data_diver', 'score': 92, 'articles': 8},
]

top_scorers = sorted(api_users, key=itemgetter('score'), reverse=True)[:3]

# attrgetter for our internal User objects
class User:
    def __init__(self, username, score, articles):
        self.username = username
        self.score = score
        self.articles = articles

users = [User(u['username'], u['score'], u['articles']) for u in api_users]
top_users = sorted(users, key=attrgetter('score'), reverse=True)

Quick Decision Guide

You have... Use... Example key
List of dictionaries itemgetter itemgetter('price')
List of tuples itemgetter itemgetter(1)
List of objects attrgetter attrgetter('price')
Nested attributes attrgetter attrgetter('address.city')

Both functions make your sorting and grouping code faster and cleaner. The next time you reach for a lambda to access a key or attribute, ask yourself: can itemgetter or attrgetter do this with less code and better performance?

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.