Revertendo strings e sequências em Python: o que funciona na prática
A gente precisa reverter coisas o tempo todo. Dados, strings, listas de configuração, logs. E tem mais de uma forma de fazer isso em Python. A escolha errada é um problema silencioso que apareceu no meu code review semana passada — alguém estava usando reversed() e depois passando o resultado pra várias funções, esperando que ele "resetasse". Não resetou. O iterator estava vazio na segunda chamada, e o bug só apareceu em produção.
ao contrário ou o contrário
Antes de entrar nos métodos, vale um minuto pra esclarecer a confusão linguística que acontece quando o pessoal escreve sobre isso. Em português, "ao contrário" se refere à direção inversa — percorrer de trás pra frente. "O contrário" é o oposto conceitual. Na prática de programação, a dúvida real não é semântica, e sim técnica: qual abordagem usar e quando cada uma falha. Eu costumo ver o termo "ao contrário ou o contrário" aparecer em fóruns quando o pessoal tenta generalizar demais. O que importa mesmo é o mecanismo.
Slicing com [::-1]
É a abordagem mais óbvia e, na maioria dos casos, a certa. Você cria uma cópia totalmente nova da sequência invertida. Funciona com strings, listas, tuplas e qualquer objeto que suporte slicing. Exemplo rápido:
"olá"[::-1] vira "ál". Simples, direto, sem surpresas. Eu uso isso pra transformar strings, inverter linhas de um arquivo antes de processar, e montar chaves de cache invertidas quando o design do sistema exige. As desvantagens são reais. Slice cria uma cópia completa na memória. Se você tá invertendo um objeto grande — uma lista de milhões de elementos ou uma string enorme — o dobro de memória aparece do nada. Além disso, slicing não funciona em iteradores genéricos ou em arquivos abertos. Se você receber um generator de uma API, [::-1] não vai existir no objeto e vai dar erro.
A função reversed()
reversed() devolve um iterator que produz os elementos na ordem inversa. Não cria cópia. Isso economiza memória e é rápido pra percorrer uma vez. O problema é que ele é um iterator consumível. Depois de passar por ele, acabou. Tem gente que esquece isso e chama list(reversed(seq)) duas vezes no mesmo código achando que a segunda chamada ainda funciona. Não funciona. Outro detalhe importante: reversed() só funciona em objetos que implementam o protocolo __reversed__ ou que são sequências com __len__ e __getitem__. Listas, tuplas, strings e ranges funcionam. Dicionários, conjuntos e generators comuns não. Se você passar um set, o Python vai reclamar.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Um caso concreto que eu tive: processei um arquivo de log de 2 GB linha por linha usando reversed() num arquivo aberto com open(). Não funcionou porque arquivo não suporta __reversed__. A solução foi carregar os índices das posições das quebras de linha num array separado, fazer o seek manual e ler de trás pra frente. Levou mais tempo pra implementar, mas usou memória constante em vez de carregar tudo pro RAM.
join com generator invertido
Quando o objetivo é construir uma string nova a partir de caracteres invertidos, ''.join(reversed(string)) é uma opção válida e às vezes mais legível que o slicing. A diferença prática entre ''.join(reversed(s)) e s[::-1] é pequena. Slicing tende a ser ligeiramente mais rápido porque é uma operação nativa otimizada em C. join com reversed adiciona uma camada de chamada de função. Num benchmark simples, a diferença fica em torno de 10-15% a favor do slicing para strings de tamanho médio. Pra strings curtas, a diferença some dentro da margem de erro. Eu prefiro join com reversed quando o código já usa iterators em outros pontos e quero manter consistência de estilo, não por performance.
Manually invertendo com loop
Tem gente que escreve loops manuais pra inverter. for i in range(len(seq)-1, -1, -1): ... Isso funciona, mas é lento e verboso. A única razão aceitável pra fazer isso é quando você precisa de lógica customizada no meio do caminho — filtrar certos elementos enquanto inverte, por exemplo. Se o objetivo é só inverter, use as opções acima.
Quando nenhuma dessas opções funciona
Se você trabalha com fluxos de dados externos — streams de rede, arquivos muito grandes, dados vindos de uma API paginada — inverter tudo numa estrutura em memória pode ser inviável. Nesse cenário, as opções são limitar quanto você armazena, usar buffering seletivo ou, quando possível, evitar a inversão completamente redesenhando o fluxo pra processar na ordem natural. Inversão forçada em streaming é uma receita pra problemas de memória e latência.
Resumo prático
Se você tem uma sequência em memória e quer o oposto invertido de uma vez, use slicing [::-1]. Se precisa economizar memória e vai percorrer apenas uma vez, reversed() é mais adequado. Se o objeto não suporta slicing nem o protocolo de reversão, você precisa adaptar o approach ou mudar a forma como os dados chegam pro seu código. A escolha errada não quebra nada imediatamente — ela aparece como bug intermitente ou pico de memória horas depois.