Python
Programming
Data Structures
Object Attributes
List Operations

Find object in list that has attribute equal to some value that meets any condition

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Searching a list of Python objects by attribute is a very common task, especially when the match is based on a rule instead of a fixed literal. The cleanest approach is usually to combine getattr, a predicate function, and next so you can express the condition directly and stop at the first match.

Finding the first matching object

Assume you have a list of records and want the first object whose status is "open" and whose priority is at least 3.

python
1from dataclasses import dataclass
2
3
4@dataclass
5class Ticket:
6    id: int
7    status: str
8    priority: int
9
10
11tickets = [
12    Ticket(1, "closed", 1),
13    Ticket(2, "open", 2),
14    Ticket(3, "open", 4),
15]
16
17match = next(
18    (ticket for ticket in tickets if ticket.status == "open" and ticket.priority >= 3),
19    None,
20)
21
22print(match)

next(..., None) returns the first matching object or None if nothing matches. This is better than building a whole temporary list when you only need one result.

Using a reusable predicate

When the condition changes often, move it into a function. That keeps the search logic readable and easy to test.

python
1def is_important_open_ticket(ticket: Ticket) -> bool:
2    return ticket.status == "open" and ticket.priority >= 3
3
4
5match = next((ticket for ticket in tickets if is_important_open_ticket(ticket)), None)
6print(match)

This pattern scales well when the condition includes multiple fields, date checks, or membership tests.

Searching by a dynamic attribute name

Sometimes the attribute itself is chosen at runtime. In that case, getattr is the right tool.

python
1from typing import Any, Callable, Iterable
2
3
4def find_by_attr(
5    items: Iterable[Any],
6    attr_name: str,
7    predicate: Callable[[Any], bool],
8):
9    return next(
10        (item for item in items if hasattr(item, attr_name) and predicate(getattr(item, attr_name))),
11        None,
12    )
13
14
15match = find_by_attr(tickets, "priority", lambda value: value >= 3)
16print(match)

Here, the caller decides both which attribute to inspect and what counts as a valid value. That is a flexible approach for filters in APIs, search utilities, or command-line tools.

Matching with any for more complex conditions

If the attribute is itself a collection, any often reads better than nested loops. Imagine each object has a tags field and you want the first ticket with any tag starting with "prod-".

python
1@dataclass
2class TaggedTicket:
3    id: int
4    tags: list[str]
5
6
7tagged = [
8    TaggedTicket(10, ["ui", "low"]),
9    TaggedTicket(11, ["prod-db", "urgent"]),
10    TaggedTicket(12, ["docs"]),
11]
12
13match = next(
14    (
15        item
16        for item in tagged
17        if any(tag.startswith("prod-") for tag in item.tags)
18    ),
19    None,
20)
21
22print(match)

That combines object-level filtering with attribute-level rules in a single expression.

When you need all matches instead of one

If you want every matching object, use a list comprehension instead of next:

python
important = [ticket for ticket in tickets if ticket.status == "open" and ticket.priority >= 3]
print(important)

Use next when the first match is enough. Use a list comprehension when the full set matters.

Common Pitfalls

The biggest mistake is forgetting the default argument to next. Without it, a missing result raises StopIteration, which is often not what you want in application code.

Another common issue is accessing attributes that may not exist. getattr(item, "priority") raises AttributeError unless you guard it with hasattr or pass a default value.

Be careful with truthy and falsy values. If the attribute may legitimately be 0, False, or an empty string, do not write logic that treats all falsy values as missing.

Finally, avoid filter plus lambda when it makes the condition harder to read. Python supports it, but a generator expression is usually clearer for object searches.

Summary

  • Use next((item for item in items if condition), None) to return the first matching object.
  • Move the condition into a helper function when the rule is reused or complex.
  • Use getattr when the attribute name is dynamic.
  • Combine any with generator expressions for collection-based attribute checks.
  • Choose next for a single result and a list comprehension when you need all matches.

Course illustration
Course illustration

All Rights Reserved.