Virando Peixe - Cozinhar churrasco mãos de peixe virando pedaços de peixe na grelha ...
Cozinhar churrasco mãos de peixe virando pedaços de peixe na grelha ...

O que é e como funciona na prática

Virando peixe é o nome que os programadores brasileiros deram para a operação de inverter uma sequência — seja string, lista ou array. A lógica é simples, mas tem uns detalhes que quem só fez curso online nunca vai te contar.

O jeito mais básico em Python é usar slicing: frase = "olá mundo"
invertida = frase[::-1]

Isso retorna "odnum alo". Funciona para strings, listas e tuplas. O mecanismo é direto: você pede do início ao fim com passo -1. A memória alocada é proporcional ao tamanho da entrada, então arrays gigantes vão consumir RAM de forma visível.

Virando peixe com múltiplos tipos de dados

Se você precisa invertir números sem transformar tudo em string antes, o jeito é converter, inverter e converter de volta. Um exemplo real: numero = 1234567890
invertido = int(str(numero)[::-1])

O resultado é 0987654321, que como inteiro vira 987654321. Percebeu o problema? zeros à esquerda somem. Isso importa se você está lidando com CEPs, números de telefone ou identificadores que não podem perder o zero. O trabalho que eu tive com isso foi num sistema de geração de códigos de barras onde o campo precisava ser invertido character por character e depois empacotado em protobuf. O primeiro deploy veio com 3% de falha porque os códigos que terminavam em zero estavam chegando truncados. Minha solução foi manter tudo como string do início ao fim e só converter pra int na hora da query final. Cortei o bug rate em 97%.

Para listas, o comportamento é mais tranquilo: lista = [1, 2, 3, 4, 5]
invertida = lista[::-1]

Retorna [5, 4, 3, 2, 1]. Função interna, escrita em C, então é mais rápida que qualquer loop manual que você escreva. Tem outras abordagens. Você pode usar reversed() junto com list():

👉 Clique no botão abaixo para saber mais sobre o assunto!

invertida = list(reversed(lista)) O retorno é um iterador. Se você chamar list() em cima, vira lista de novo. A diferença prática entre slicing e reversed() é que slicing cria uma cópia imediata enquanto reversed() é lazy. Em listas pequenas isso não faz diferença, mas em processamento de arquivos grandes com milhões de linhas, o reversed() usa menos memória no início porque não materializa tudo de uma vez.

Outra opção é o método .reverse() in-place: lista.reverse()

Esse modifica a lista original e retorna None. Útil quando você não quer ou não precisa manter o estado anterior. A desvantagem é que se você passar essa lista pra outra função no meio do caminho, o dado já foi alterado e pode causar efeitos colaterais difíceis de rastrear. Já vi gente levar horas caçando bug porque alguém chamou .reverse() numa variável que era shared entre threads. Para strings, não existe método .reverse() porque strings são imutáveis em Python. Você sempre vai acabar criando uma nova string. Isso é importante porque em sistemas com muita concatenação de strings invertidas, o garbage collector vai trabalhar dobrado. Eu vi um serviço de logs que processava cerca de 200 mil linhas por segundo invertendo campos e o uso de memória subir de 400MB para 1.2GB só por causa disso. Migrei pra um gerador com reversed() e genérico drop-by-drop e o consumo caiu pra 600MB estável.

Quando virar peixe não é a solução certa

Tem casos em que inverter a sequência toda é custo sem benefício. Se você só precisa do último elemento, use indexação negativa em vez de inverter tudo: ultimo = lista[-1]

Isso é O(1). Virar peixe seria O(n) e ainda alocaria memória extra desnecessariamente. Para verificar se uma string é palíndromo, comparar os extremos com dois ponteiros (um no início, outro no fim) é mais eficiente do que inverter a string inteira e comparar. Em Python isso é menos relevante por causa da otimização do CPython, mas em outras linguagens a diferença é gritante. Se você está trabalhando com dados que vêm em streaming — como leitura de arquivo linha por linha ou requisições HTTP — inverter tudo numa lista antes de processar vai estourar a memória facilmente. O correto nesse caso é processar na ordem reversa usando um deque ou acumulador, dependendo do cenário.

Uma limitação que muita gente não considera: virando peixe em arrays numpy com np.flip() cria um view quando possível, mas em certas configurações de dtype e shape ele força um copy completo. Se seu array é de 10GB e você fizer flip sem verificar, vai ter um pico de 20GB de memória. Sempre cheque o owndata do array resultante. Outro ponto: se a sequência contém objetos mutáveis (listas dentro de listas, dicionários dentro de tuplas), o slicing faz shallow copy. Os elementos internos são compartilhados, não copiados. Mudar um item dentro de um sublist invertida vai refletir na original. Pra deep copy, use copy.deepcopy(), mas prepare-se pro custo computacional — em estruturas grandes isso pode ser 10x mais lento que o slicing puro.

Resumindo sem resumo: use slicing para o dia a dia, reversed() quando precisar de economia de memória em pipelines grandes, e .reverse() apenas quando tiver certeza absoluta de que o in-place é o que você quer. E não esqueça de checar se realmente precisa inverter a sequência toda antes de começar.