O módulo linecache oferece acesso eficiente a linhas específicas de arquivos de texto, com foco especial em código-fonte Python. Ele é usado internamente por ferramentas como traceback, debuggers, analisadores e sistemas de diagnóstico para recuperar a linha associada a um frame sem reler o arquivo inteiro a cada consulta.
A API parece simples, mas envolve cache global, detecção de alterações, suporte a módulos carregados de formas especiais e cuidados com encoding. Entender esse comportamento ajuda a criar ferramentas de análise, relatórios de erro e interfaces de debugging mais confiáveis.
Leia uma linha específica
A função principal é linecache.getline(filename, lineno). A numeração começa em 1.
import linecache
linha = linecache.getline("aplicacao.py", 12)
print(linha)
Se a linha existir, o retorno normalmente inclui o caractere de nova linha final. Se o arquivo ou número não puder ser lido, a função retorna uma string vazia em vez de lançar a maioria dos erros comuns.
Numeração começa em um
Diferente de listas Python, a primeira linha é a linha 1. Isso acompanha tracebacks, editores e mensagens do compilador.
primeira = linecache.getline("app.py", 1)
Validar o número antes da consulta evita confundir zero, valores negativos e linhas inexistentes.
Retorno vazio
Uma string vazia pode significar arquivo inexistente, linha fora do intervalo, erro de leitura ou entrada não disponível. A API favorece o uso em diagnósticos, onde falhar silenciosamente ao recuperar o trecho é melhor que esconder a exceção original.
Se sua aplicação precisa distinguir causas, valide o caminho e leia o arquivo diretamente com tratamento explícito.
O cache global
Depois da primeira leitura, o módulo mantém informações em um cache global do processo. Consultas posteriores evitam abrir e percorrer o arquivo repetidamente.
Esse comportamento é útil quando um traceback busca várias linhas do mesmo arquivo. Porém, ferramentas de longa duração precisam considerar arquivos modificados e consumo de memória.
Atualize arquivos alterados
checkcache() compara metadados e remove entradas que parecem desatualizadas.
linecache.checkcache("aplicacao.py")
linha = linecache.getline("aplicacao.py", 12)
Sem um filename, a função verifica todas as entradas apropriadas. Em um editor ou servidor de desenvolvimento, execute essa verificação antes de exibir fonte que pode ter mudado.
Limpe o cache
clearcache() remove todas as linhas armazenadas.
linecache.clearcache()
Isso pode ser útil após processar muitos arquivos, trocar um workspace ou concluir uma análise batch. A próxima consulta recarregará o conteúdo.
Não limpe a cada chamada
Limpar constantemente elimina o benefício do módulo. Prefira invalidar quando há uma mudança conhecida, ao trocar projetos ou quando a memória do processo realmente exige.
Em ferramentas interativas, um file watcher pode acionar checkcache() para arquivos modificados.
getline com module_globals
getline() aceita um terceiro argumento opcional, module_globals. Ele pode ajudar a localizar fonte de módulos cujo loader fornece o código sem um arquivo convencional.
linha = linecache.getline(
nome_arquivo,
numero,
module_globals=globals_do_modulo,
)
Essa integração é relevante para import hooks, arquivos zip, módulos congelados e loaders personalizados.
Loaders e get_source
Quando há um loader compatível, linecache pode solicitar o código por meio de métodos do sistema de importação, como get_source(). Isso explica por que um traceback às vezes mostra fonte mesmo quando o caminho não representa um arquivo comum no disco.
Loaders personalizados devem implementar contratos de importação corretamente para cooperar com ferramentas de diagnóstico.
Arquivos em zip
Aplicações distribuídas em ZIP ou .pyz podem ter módulos sem arquivos extraídos. O mecanismo de loader permite recuperar a fonte quando ela está incluída no arquivo.
Leia o guia de zipapp no Python para entender como aplicações .pyz são construídas.
Arquivos gerados
Código criado dinamicamente pode usar nomes simbólicos no argumento filename de compile(). Se não houver uma fonte associada ao cache ou a um loader, linecache não conseguirá recuperar a linha.
Ferramentas que compilam código gerado podem registrar as linhas no cache com muito cuidado, mas isso depende de detalhes internos e deve ser testado por versão.
Tracebacks
O módulo traceback usa linecache para mostrar a linha de fonte correspondente a cada frame.
try:
executar()
except Exception:
traceback.print_exc()
Se o arquivo mudou depois que o código foi carregado, a linha exibida pode não corresponder ao bytecode em execução. Esse problema é comum em deploys que substituem arquivos sem reiniciar processos.
Código e fonte precisam corresponder
Evite alterar arquivos usados por um processo vivo sem reiniciá-lo. O runtime executa code objects antigos enquanto linecache pode ler a versão nova, produzindo diagnósticos enganosos.
Deploys atômicos com diretórios versionados e restart controlado preservam a correspondência.
Encoding de fonte Python
Arquivos Python podem declarar encoding. Linecache coopera com mecanismos de tokenização para ler a fonte de modo compatível com o interpretador.
Para análise completa de um arquivo, tokenize.open() é uma escolha explícita. Veja tokenize no Python.
Nova linha final
As linhas retornadas normalmente terminam com \n. Use rstrip("\n") apenas quando a interface não quiser a quebra.
texto = linecache.getline(caminho, numero).rstrip("\n")
Não use strip() indiscriminadamente, pois ele removeria a indentação significativa do código.
Preserve a indentação
Em relatórios de erro, espaços e tabs mostram a estrutura do bloco. Remover whitespace inicial prejudica a compreensão e pode distorcer indicadores de coluna.
Ao destacar a linha, mantenha o texto original e adicione o marcador em uma linha separada.
Indicador de coluna
Linecache recupera a linha, mas não interpreta offsets. Tracebacks e SyntaxError podem fornecer coluna inicial e final.
linha = linecache.getline(erro.filename, erro.lineno)
marcador = " " * (erro.offset - 1) + "^"
Unicode, tabs e offsets em bytes exigem cuidado. Para interfaces precisas, use as posições fornecidas pela AST ou pelo tokenizer.
Ferramenta de contexto
Você pode exibir algumas linhas antes e depois do ponto de interesse.
def contexto(caminho, linha, raio=2):
inicio = max(1, linha - raio)
fim = linha + raio
return [
(numero, linecache.getline(caminho, numero))
for numero in range(inicio, fim + 1)
]
Ignore linhas vazias retornadas além do fim e limite o raio para não expor conteúdo demais.
Mensagens de erro melhores
Linters e validadores podem combinar filename, linha, coluna, mensagem e trecho.
config.py:18:7: valor inválido
timeout = -1
^Evite copiar arquivos inteiros para logs. Um contexto curto é mais legível e reduz exposição de segredos.
Segurança
Não aceite um caminho arbitrário de um usuário e o passe diretamente a linecache. A função pode ler arquivos acessíveis ao processo.
Restrinja consultas a um workspace conhecido, normalize paths e verifique que o resultado continua dentro da raiz permitida.
Validação de caminho
from pathlib import Path
raiz = Path("projeto").resolve()
alvo = (raiz / caminho_usuario).resolve()
if alvo != raiz and raiz not in alvo.parents:
raise ValueError("arquivo fora do projeto")
Também considere symlinks, permissões e arquivos que mudam entre a validação e a leitura.
Privacidade em relatórios
Linhas de código podem conter endpoints internos, nomes de clientes, consultas e até segredos colocados incorretamente no fonte. Trate trechos como dados sensíveis.
Sanitize relatórios enviados a sistemas externos e aplique controles de retenção.
Concorrência
O cache é global ao processo. Ferramentas com várias threads podem consultar simultaneamente, mas operações de invalidação e arquivos mutáveis tornam o resultado temporalmente variável.
Não dependa de linecache como snapshot consistente. Se precisa analisar uma versão fixa, leia o arquivo uma vez e mantenha seu próprio conteúdo imutável.
Processos separados
Cada processo possui seu próprio cache. Limpar no pai não afeta workers e vice-versa.
Em análise distribuída, envie diagnósticos compactos em vez de depender de um cache compartilhado inexistente.
Memória
Processar milhares de arquivos pode deixar muitas linhas armazenadas. Chame clearcache() ao concluir um lote ou ao trocar de repositório.
Meça antes de otimizar. O cache pode ser pequeno em uma ferramenta normal e valioso para desempenho.
Arquivos muito grandes
Linecache foi projetado para acesso conveniente a fonte, não para consultar linhas aleatórias em arquivos gigantes de dados. O carregamento pode manter uma lista de linhas na memória.
Para logs enormes ou datasets, use índices, seek, mmap ou formatos apropriados.
Arquivos temporários
Se um arquivo temporário for removido depois que entrou no cache, consultas podem continuar retornando linhas antigas até uma verificação ou limpeza.
Isso pode ser útil para tracebacks tardios, mas também confunde ferramentas que esperam refletir o filesystem atual.
checkcache e timestamps
A detecção se baseia em metadados disponíveis. Filesystems com baixa resolução de timestamp, sincronização remota ou substituições rápidas podem produzir casos inesperados.
Quando a exatidão importa, use conteúdo versionado ou hashes em sua própria camada.
Monkey patching e notebooks
Ambientes interativos geram nomes e fontes de células por mecanismos próprios. IPython e notebooks mantêm caches adicionais para permitir tracebacks.
Não assuma que um filename entre sinais de menor e maior corresponde a um arquivo real.
Integração com inspect
inspect.getsource() também depende de informações de arquivo e caches para recuperar código de funções e classes.
Funções dinâmicas, builtins e extensões nativas podem não ter fonte disponível. Trate a ausência como resultado normal.
Integração com faulthandler
faulthandler produz pilhas mínimas em falhas graves. Depois do incidente, ferramentas podem usar linecache para enriquecer filenames e linhas quando a fonte correspondente ainda existe.
Veja faulthandler no Python.
Testes
Teste primeira e última linha, arquivo ausente, linha fora do intervalo, encoding diferente, arquivo alterado, cache limpo, loader personalizado, módulo em ZIP e path não confiável.
Crie arquivos temporários controlados e restaure o cache entre testes para evitar dependência de estado global.
Evite testar detalhes internos
O dicionário interno de cache existe, mas seu formato não é uma API estável para aplicações. Prefira getline(), checkcache() e clearcache().
Se uma ferramenta precisa injetar fonte virtual, isole essa integração e teste cada versão suportada.
Quando ler diretamente
Use Path.read_text() ou tokenize.open() quando precisa de todos os dados, erros explícitos, snapshot consistente ou controle de encoding.
Use linecache quando o problema é recuperar rapidamente uma linha para diagnóstico.
Erros comuns
Os erros mais frequentes são usar índice zero, interpretar retorno vazio como linha vazia real, remover indentação com strip(), esquecer que o cache pode estar desatualizado, aceitar paths arbitrários, usar o módulo para arquivos gigantes e presumir que código em execução corresponde ao arquivo atual.
Conclusão
linecache é uma pequena infraestrutura essencial para tracebacks e ferramentas de desenvolvimento. Use getline() para linhas pontuais, checkcache() quando arquivos mudam e clearcache() ao terminar grandes lotes.
Preserve indentação, proteja caminhos e não trate o cache como snapshot imutável. Consulte a documentação oficial de linecache e o guia de tokenize no Python.







