operator.attrgetter: ordene objetos por atributos

Publicado em: 02/09/2026
Tempo de leitura: 5 minutos
Desenvolvedor organizando dados com operator.attrgetter no Python

Ao trabalhar com listas de objetos em Python, é comum precisar ordenar, agrupar, filtrar ou transformar dados com base em um atributo. A solução mais conhecida é usar uma função lambda, como lambda item: item.nome. Ela funciona bem, mas existe uma alternativa da biblioteca padrão que torna a intenção mais explícita: operator.attrgetter. Essa função cria um callable especializado em recuperar atributos, inclusive atributos aninhados, e pode ser reutilizada em várias operações.

Neste guia, você aprenderá como usar operator.attrgetter no Python, quando ele é melhor do que uma lambda, como acessar vários atributos, como trabalhar com caminhos aninhados, quais erros podem ocorrer e como aplicar a técnica em código real. O objetivo não é substituir todas as lambdas, e sim escolher a ferramenta que deixa a regra mais legível.

O que é operator.attrgetter

attrgetter pertence ao módulo operator, que oferece funções equivalentes a diversas operações da linguagem. Em vez de escrever uma função manual para buscar um atributo, você informa o nome desejado e recebe uma função pronta.

from operator import attrgetter

obter_nome = attrgetter("nome")
print(obter_nome(usuario))

O objeto devolvido por attrgetter é chamável. Isso significa que ele pode ser passado diretamente para parâmetros como key em sorted, min, max e itertools.groupby. Essa composição combina muito bem com conceitos apresentados no artigo sobre ordenação com sort e sorted.

Ordenando objetos por atributo

Considere uma classe que representa produtos:

from dataclasses import dataclass
from operator import attrgetter

@dataclass
class Produto:
    nome: str
    preco: float
    estoque: int

produtos = [
    Produto("Teclado", 180.0, 8),
    Produto("Mouse", 90.0, 15),
    Produto("Monitor", 1200.0, 4),
]

ordenados = sorted(produtos, key=attrgetter("preco"))

O resultado é uma nova lista ordenada pelo preço. A chamada é equivalente a sorted(produtos, key=lambda p: p.preco). A diferença principal é semântica: attrgetter("preco") comunica diretamente que a chave é um atributo. Em bases de código maiores, isso reduz ruído e facilita a leitura.

Para ordenar em ordem decrescente, use reverse=True. Para encontrar o produto mais caro, combine com max:

mais_caro = max(produtos, key=attrgetter("preco"))

Acessando atributos aninhados

Um dos recursos mais úteis é a notação com ponto. Se um pedido possui um cliente e o cliente possui um endereço, você pode acessar um caminho completo:

obter_cidade = attrgetter("cliente.endereco.cidade")
cidade = obter_cidade(pedido)

Internamente, o getter percorre os atributos na ordem informada. Essa abordagem evita lambdas longas como lambda p: p.cliente.endereco.cidade. Ela é especialmente interessante em relatórios, tabelas, serializadores e pipelines de dados.

É importante entender que a notação pressupõe que todos os objetos intermediários existam. Se cliente for None, ocorrerá AttributeError. Quando os dados são opcionais, uma função normal com validação costuma ser mais adequada.

Obtendo vários atributos de uma vez

attrgetter aceita mais de um nome. Nesse caso, o retorno é uma tupla:

chave = attrgetter("nome", "preco")
print(chave(produtos[0]))
# ('Teclado', 180.0)

Isso é útil para ordenação por múltiplos critérios. O Python compara tuplas item por item, então você pode ordenar primeiro por estoque e depois por nome:

ordenados = sorted(produtos, key=attrgetter("estoque", "nome"))

A estabilidade da ordenação do Python garante comportamento previsível quando as chaves são iguais. Para entender melhor esse mecanismo, vale revisar o guia sobre sort e sorted no Python.

attrgetter com groupby

Outra combinação poderosa é com itertools.groupby. Antes de agrupar, os dados precisam estar ordenados pela mesma chave:

from itertools import groupby
from operator import attrgetter

produtos_ordenados = sorted(produtos, key=attrgetter("estoque"))

for estoque, grupo in groupby(produtos_ordenados, key=attrgetter("estoque")):
    print(estoque, list(grupo))

O detalhe da ordenação é indispensável, porque groupby agrupa elementos consecutivos, não todos os valores iguais espalhados pela sequência. O artigo sobre itertools no Python ajuda a compreender esse modelo de processamento preguiçoso.

Diferenças entre attrgetter, itemgetter e methodcaller

O módulo operator possui ferramentas relacionadas. attrgetter lê atributos de objetos. itemgetter lê itens por índice ou chave, sendo apropriado para listas, tuplas e dicionários. methodcaller cria uma função que chama um método.

from operator import itemgetter, methodcaller

itemgetter("nome")({"nome": "Ana"})
methodcaller("strip")("  texto  ")

Escolha a função de acordo com o contrato dos dados. Para um objeto com usuario.nome, use attrgetter. Para um dicionário com usuario["nome"], use itemgetter. Misturar os dois modelos costuma indicar que a estrutura de dados precisa ser melhor definida.

Quando uma lambda ainda é melhor

attrgetter é ideal quando a chave consiste somente em recuperar atributos. Quando há transformação, validação, valor padrão ou cálculo, uma lambda ou função nomeada é mais clara.

ordenados = sorted(produtos, key=lambda p: p.preco * (1 - p.desconto))

Também prefira uma função normal quando precisar tratar atributos ausentes:

def cidade_segura(pedido):
    cliente = getattr(pedido, "cliente", None)
    endereco = getattr(cliente, "endereco", None)
    return getattr(endereco, "cidade", "")

A função getattr aceita valor padrão, enquanto attrgetter não oferece essa opção. Para fundamentos de funções e composição, consulte o artigo sobre funções em Python.

Desempenho e reutilização

Em muitos cenários, attrgetter pode ser ligeiramente mais eficiente que uma lambda equivalente, pois é implementado em código otimizado da biblioteca padrão. No entanto, a diferença raramente deve ser o motivo principal da escolha. Legibilidade, intenção e manutenção são critérios mais importantes.

Quando o mesmo acesso aparece repetidamente, crie o getter uma vez:

por_data = attrgetter("criado_em")
registros = sorted(registros, key=por_data)
mais_recente = max(registros, key=por_data)

Isso evita repetir strings e centraliza a regra. Em projetos maiores, getters reutilizáveis podem ficar perto dos modelos ou da camada de relatório.

Cuidados com propriedades e descriptors

attrgetter usa o acesso normal de atributos. Portanto, ele executa propriedades, descriptors e __getattr__. Se uma propriedade faz acesso ao banco, rede ou cálculo caro, ordenar uma lista pode disparar a operação muitas vezes. Não trate attrgetter como uma ferramenta de introspecção estática.

Quando for necessário inspecionar membros sem executar descriptors, a biblioteca inspect possui alternativas específicas. O guia sobre fluxo e retorno de funções também ajuda a estruturar funções de chave sem efeitos colaterais.

Boas práticas

Use nomes de atributos estáveis e evite construir caminhos a partir de entrada não confiável. Trate AttributeError na fronteira onde dados incompletos entram no sistema. Ordene antes de usar groupby. Prefira uma função nomeada quando a regra envolver mais do que leitura direta. Escreva testes para chaves compostas e caminhos aninhados.

Para detalhes oficiais, consulte a documentação de operator.attrgetter e a documentação de ordenação do Python.

Conclusão

operator.attrgetter é uma ferramenta pequena, mas muito útil para deixar ordenações, agrupamentos e transformações mais declarativos. Ele funciona com atributos simples, caminhos aninhados e múltiplos campos, integrando-se naturalmente a sorted, min, max e groupby. Use-o quando a operação for apenas recuperar atributos. Quando houver regras extras, valores padrão ou efeitos colaterais, uma função explícita continuará sendo a melhor escolha.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Programação assíncrona com asyncio.Runner no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    asyncio.Runner: reutilize o event loop com segurança

    Aprenda asyncio.Runner no Python para reutilizar o event loop, controlar contexto, sinais, debug e encerramento assíncrono com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    02/09/2026
    Compressão de dados binários com Zstandard no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Zstandard com streams e dicionários

    Aprenda compression.zstd no Python para compactar dados com Zstandard, usar streaming, dicionários e limites seguros.

    Ler mais

    Tempo de leitura: 7 minutos
    01/09/2026
    Aplicação Python empacotada como arquivo executável com zipapp
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    zipapp no Python: crie apps executáveis

    Aprenda zipapp no Python para empacotar aplicações em um arquivo pyz executável, portátil e simples de distribuir.

    Ler mais

    Tempo de leitura: 6 minutos
    01/09/2026
    Código Python usado para compor funções com functools.Placeholder
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    functools.Placeholder: partial com lacunas posicionais

    Aprenda functools.Placeholder no Python para preencher argumentos posicionais flexíveis com partial e criar APIs funcionais mais claras.

    Ler mais

    Tempo de leitura: 5 minutos
    31/08/2026
    Pessoa programando e analisando dados em Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    itertools.pairwise: compare elementos vizinhos

    Aprenda itertools.pairwise no Python para comparar elementos vizinhos, detectar mudanças e criar pipelines claros e eficientes.

    Ler mais

    Tempo de leitura: 4 minutos
    31/08/2026
    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    types.new_class no Python: classes dinâmicas

    Aprenda types.new_class no Python para gerar classes dinâmicas com metaclasses, namespaces preparados, herança e metadados corretos.

    Ler mais

    Tempo de leitura: 4 minutos
    30/08/2026