How do I sort a list of objects based on an attribute of the objects in Python?

To sort a list of objects based on an attribute in Python, use the sorted() function or the list.sort() method with the key parameter. Here’s a detailed explanation with examples:

1. Basic Sorting by a Single Attribute

Use the key parameter to specify the attribute for comparison.

Example: Sort by a numeric attribute (e.g., age)

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 (ascending)
sorted_people = sorted(people, key=lambda x: x.age)

# Output order: Bob (25), Alice (30), Charlie (35)

Sort in descending order:

people.sort(key=lambda x: x.age, reverse=True)
# Output order: Charlie (35), Alice (30), Bob (25)

2. Sorting by a String Attribute (e.g., name)

# Sort alphabetically by name (case-sensitive)
sorted_people = sorted(people, key=lambda x: x.name)
# Output order: Alice, Bob, Charlie

# Sort case-insensitively
sorted_people = sorted(people, key=lambda x: x.name.lower())

3. Sorting by Multiple Attributes

Use a tuple in the key function to prioritize attributes.

Example: Sort by age first, then name

people = [
    Person("Alice", 30),
    Person("David", 30),
    Person("Bob", 25),
    Person("Charlie", 35)
]

# Sort by age (ascending), then name (ascending)
sorted_people = sorted(people, key=lambda x: (x.age, x.name))
# Output order: Bob (25), Alice (30), David (30), Charlie (35)

4. Using operator.attrgetter for Cleaner Code

The attrgetter function from the operator module simplifies attribute access.

from operator import attrgetter

# Sort by age
sorted_people = sorted(people, key=attrgetter('age'))

# Sort by multiple attributes
sorted_people = sorted(people, key=attrgetter('age', 'name'))

5. Sorting Custom Objects with __lt__ (Advanced)

Implement the __lt__ method in your class to define natural ordering.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __lt__(self, other):
        return self.age < other.age  # Sort by age by default

people = [Person("Alice", 30), Person("Bob", 25)]
people.sort()  # Uses __lt__ to compare

6. Handling Edge Cases

Missing Attributes

Ensure all objects have the attribute used for sorting, or handle exceptions:

try:
    sorted_people = sorted(people, key=lambda x: x.age)
except AttributeError:
    print("One or more objects lack the 'age' attribute!")

None Values

Use a default value for None attributes:

sorted_people = sorted(people, key=lambda x: x.age if x.age is not None else 0)

Full Example Workflow

from operator import attrgetter

class Book:
    def __init__(self, title, author, year):
        self.title = title
        self.author = author
        self.year = year

books = [
    Book("The Hobbit", "J.R.R. Tolkien", 1937),
    Book("1984", "George Orwell", 1949),
    Book("Brave New World", "Aldous Huxley", 1932)
]

# Sort by publication year (ascending)
sorted_books = sorted(books, key=attrgetter('year'))
# Output: Brave New World (1932), The Hobbit (1937), 1984 (1949)

# Sort by author name (case-insensitive), then title
sorted_books = sorted(
    books,
    key=lambda x: (x.author.lower(), x.title)
)

Summary Table

TaskCode Example
Sort by single attributesorted(list, key=lambda x: x.attr)
Sort descendingsorted(list, key=..., reverse=True)
Sort by multiple attrskey=lambda x: (x.attr1, x.attr2)
Use attrgetterfrom operator import attrgetter; key=attrgetter('attr')

This approach works for any object with accessible attributes, including dataclasses, SQLAlchemy models, or custom classes!

Leave a Reply

Your email address will not be published. Required fields are marked *