Ferramentas de depuração, formatadores de exceções, analisadores estáticos e editores frequentemente precisam recuperar uma linha específica de um arquivo sem implementar manualmente abertura, detecção de codificação e cache. O módulo linecache no Python oferece exatamente essa infraestrutura: ele recebe um nome de arquivo e um número de linha, devolve o texto correspondente e mantém os dados em memória para acelerar acessos repetidos.
Neste guia, você aprenderá a usar getline(), entenderá o comportamento do cache, atualizará arquivos modificados com checkcache(), liberará memória com clearcache() e verá como loaders, módulos congelados e encodings são tratados. O conteúdo complementa nossos artigos sobre traceback no Python, tokenize, inspect, pathlib e filecmp.
O que o linecache resolve
A solução direta para recuperar uma linha costuma ser abrir o arquivo, ler todas as linhas e selecionar um índice:
from pathlib import Path
linhas = Path("app.py").read_text(encoding="utf-8").splitlines(True)
linha = linhas[24]Isso funciona, mas repete trabalho quando muitas consultas atingem o mesmo arquivo. Também exige lidar com encoding, arquivo inexistente, números fora do intervalo e possíveis fontes que não estão em um caminho convencional. O linecache centraliza essas decisões e é usado pelo próprio módulo traceback para mostrar a linha de código associada a uma exceção.
Primeiro exemplo com getline()
A função principal é linecache.getline(filename, lineno).
import linecache
texto = linecache.getline("app.py", 10)
print(texto, end="")Os números de linha começam em 1, como em editores e tracebacks. Se a linha existir, o texto normalmente inclui o caractere de nova linha no final. Por isso, o exemplo usa end="" para evitar uma linha em branco adicional.
Comportamento em erros
getline() não propaga erros comuns de leitura. Se o arquivo não existir, a linha estiver fora do intervalo ou ocorrer outro problema, o retorno será uma string vazia.
linha = linecache.getline("arquivo-inexistente.py", 3)
if linha == "":
print("linha não disponível")Essa característica é conveniente em relatórios de diagnóstico, onde falhar ao recuperar o código-fonte não deve esconder a exceção principal. Em aplicações que precisam distinguir arquivo ausente de linha vazia, faça validações adicionais com pathlib ou abra o arquivo diretamente.
Linha vazia versus falha
Uma linha real contendo apenas uma quebra é retornada como "\n", enquanto uma falha retorna "". A diferença permite identificar muitos casos:
if linha == "":
print("não encontrada")
elif linha == "\n":
print("linha em branco")Mesmo assim, não use linecache como validador de existência ou permissões. Sua API foi desenhada para recuperação tolerante de texto, não para diagnóstico detalhado do sistema de arquivos.
Como o cache melhora o desempenho
Na primeira consulta, o módulo lê o conteúdo necessário e armazena informações internamente. Chamadas posteriores para outras linhas do mesmo arquivo reutilizam essa entrada.
for numero in range(100, 111):
print(linecache.getline("modulo_grande.py", numero), end="")Esse padrão é útil para mostrar algumas linhas ao redor de um erro, produzir previews e processar várias referências ao mesmo arquivo. O ganho é maior quando o arquivo é consultado repetidamente durante a vida do processo.
O cache pode ficar desatualizado
Se o arquivo for alterado depois da primeira leitura, a entrada em memória pode continuar representando a versão antiga. Use checkcache() quando precisar observar mudanças no disco.
linecache.checkcache("app.py")
linha_atual = linecache.getline("app.py", 10)A função compara metadados e remove entradas que não parecem mais válidas. A próxima chamada recarrega o arquivo.
Verificar todo o cache
Sem argumento, checkcache() examina todas as entradas conhecidas.
linecache.checkcache()Isso pode ser apropriado em ferramentas interativas que acompanham muitos arquivos. Em servidores ou processos com grande quantidade de módulos, prefira verificar somente o arquivo relevante para evitar trabalho desnecessário.
Limpar entradas com clearcache()
clearcache() remove todas as linhas armazenadas.
linecache.clearcache()Use essa função quando um processamento em lote terminar, quando muitos arquivos grandes deixarem de ser necessários ou em testes que precisam de isolamento. Ela não apaga arquivos nem muda módulos carregados; apenas descarta o cache interno do linecache.
Encoding do arquivo
O módulo abre código-fonte com tokenize.open(), que detecta a declaração de encoding reconhecida pelo Python. Sem uma declaração, a codificação padrão é UTF-8.
# -*- coding: latin-1 -*-
mensagem = "olá"Essa escolha aproxima o comportamento do interpretador. A documentação oficial de linecache explica que a detecção utiliza tokenize.detect_encoding(). Para arquivos de texto que não são código Python, pode ser mais claro abrir explicitamente com o encoding definido pela aplicação.
Integração com traceback
Ao formatar uma exceção, o traceback possui nome do arquivo e número da linha. O linecache recupera o texto exibido no relatório.
import traceback
try:
resultado = 10 / 0
except ZeroDivisionError:
print(traceback.format_exc())Em debuggers e sistemas de observabilidade, você pode usar linecache para adicionar contexto sem ler manualmente o arquivo inteiro.
def contexto(filename, lineno, raio=2):
inicio = max(1, lineno - raio)
fim = lineno + raio
return [
(n, linecache.getline(filename, n))
for n in range(inicio, fim + 1)
]Números fora do intervalo
Números negativos, zero ou maiores que a quantidade de linhas produzem string vazia.
assert linecache.getline("app.py", 0) == ""
assert linecache.getline("app.py", -1) == ""Valide números recebidos por API para evitar consultas sem sentido e para devolver mensagens de erro mais claras.
Caminhos relativos
Quando o nome é relativo e não é encontrado diretamente, o linecache pode procurar usando entradas de sys.path.
linha = linecache.getline("meu_pacote/modulo.py", 5)Para arquivos de aplicação, caminhos absolutos tornam o comportamento mais previsível. Resolva o caminho com Path.resolve() quando a origem for conhecida.
Fontes fornecidas por loaders
Nem todo módulo Python vem de um arquivo comum. Um import loader pode expor o método get_source(). Se module_globals for informado e contiver um loader compatível, linecache pode recuperar o texto por essa interface.
linha = linecache.getline(
nome_virtual,
12,
module_globals=modulo.__dict__,
)Esse suporte é importante para importadores customizados, pacotes compactados e ambientes que geram módulos dinamicamente.
lazycache()
lazycache(filename, module_globals) guarda informações suficientes para buscar a fonte posteriormente, sem executar a leitura imediatamente e sem conservar o dicionário global completo.
linecache.lazycache(nome_virtual, modulo.__dict__)
# Mais tarde:
texto = linecache.getline(nome_virtual, 20)A função reduz acoplamento entre o objeto de módulo e o consumidor que precisará das linhas. Ela é especialmente útil em ferramentas de importação e depuração.
Módulos congelados no Python 3.14
Desde o Python 3.14, nomes iniciados por <frozen podem ser associados ao arquivo real por meio de module_globals['__file__'].
linha = linecache.getline(
"<frozen meu_modulo>",
8,
module_globals=globals_do_modulo,
)A melhoria torna relatórios de código congelado mais informativos quando o ambiente fornece o caminho correspondente.
Arquivos gerados e conteúdo em memória
Se você compila código com nomes virtuais, linecache não conhece automaticamente o texto original.
codigo_fonte = "def calcular():\n return 42\n"
code = compile(codigo_fonte, "<gerado>", "exec")Frameworks que desejam tracebacks com a fonte podem gerenciar entradas próprias ou fornecer loaders. Alterar diretamente detalhes internos de linecache.cache é possível, mas depende de implementação e deve ser encapsulado e testado.
Segurança com caminhos externos
Não aceite um caminho arbitrário de usuário e devolva qualquer linha do servidor. Isso pode expor código-fonte, configurações e segredos.
BASE = Path("/srv/app/fontes").resolve()
solicitado = (BASE / nome).resolve()
if BASE not in solicitado.parents:
raise ValueError("caminho fora da área permitida")Além da validação de diretório, aplique autenticação, autorização e uma lista de extensões permitidas.
Concorrência
O linecache é usado amplamente pelo runtime, mas sua API não oferece transações entre leitura, alteração do arquivo e invalidação. Um arquivo pode mudar entre checkcache() e getline().
Se a consistência exata for obrigatória, abra o arquivo uma vez, mantenha o conteúdo localmente e trabalhe sobre esse snapshot. Linecache prioriza conveniência de diagnóstico.
Testes
Use diretórios temporários para verificar leitura e invalidação.
def test_atualiza_linha(tmp_path):
arquivo = tmp_path / "exemplo.py"
arquivo.write_text("a = 1\n", encoding="utf-8")
assert linecache.getline(str(arquivo), 1) == "a = 1\n"
arquivo.write_text("a = 2\n", encoding="utf-8")
linecache.checkcache(str(arquivo))
assert linecache.getline(str(arquivo), 1) == "a = 2\n"
linecache.clearcache()Limpar o cache no final reduz interferência entre testes.
linecache versus leitura direta
Use linecache quando você precisa de linhas por número, repetidamente, especialmente em diagnósticos. Use open() ou Path.read_text() quando precisa processar o arquivo inteiro, controlar erros detalhadamente, aplicar locking ou escolher regras de encoding próprias.
Erros frequentes
- Usar índice zero em vez de número de linha iniciado em 1.
- Confundir string vazia com uma linha em branco.
- Esperar atualização automática após modificar o arquivo.
- Manter milhares de arquivos no cache sem necessidade.
- Usar caminhos relativos dependentes do diretório atual.
- Expor caminhos arbitrários em uma API.
- Presumir que toda fonte existe como arquivo físico.
- Depender diretamente da estrutura interna do cache.
Boas práticas
- Use
getline()para recuperação tolerante. - Valide números e caminhos vindos de entrada externa.
- Chame
checkcache(filename)após mudanças. - Libere entradas com
clearcache()em lotes extensos. - Passe
module_globalspara fontes não convencionais. - Trate o retorno vazio explicitamente.
- Prefira snapshots quando consistência exata for necessária.
- Teste módulos virtuais e versões suportadas.
Conclusão
O módulo linecache no Python é uma peça pequena, mas essencial, da infraestrutura de diagnóstico da linguagem. Ele recupera linhas por número, interpreta o encoding de código-fonte, reutiliza conteúdo em cache e coopera com loaders e módulos congelados.
Usado corretamente, ele simplifica tracebacks, previews e ferramentas de análise. A chave é lembrar que sua API é tolerante e orientada a diagnóstico: atualize o cache quando os arquivos mudarem, valide entradas externas e escolha leitura direta quando precisar de controle rigoroso sobre erros e consistência.





