linecache no Python: leia linhas por número

Publicado em: 07/08/2026
Tempo de leitura: 7 minutos
Editor de código com linhas numeradas representando o módulo linecache no Python

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_globals para 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.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Dados binários representando serialização interna com marshal no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    marshal no Python: serialização interna

    Aprenda marshal no Python para serializar tipos internos, controlar versões e bloquear objetos de código com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    06/08/2026
    Monitor com código binário representando personalização de pickle com copyreg no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    copyreg no Python: personalize o pickle

    Aprenda copyreg no Python para registrar funções de redução, personalizar pickle e preservar compatibilidade de objetos.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    functools.partial no Python: guia prático

    Aprenda functools.partial no Python para fixar argumentos, adaptar callbacks e criar funções especializadas com clareza.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    filecmp no Python: compare arquivos e pastas

    Aprenda filecmp no Python para comparar arquivos e pastas, usar shallow, dircmp, cmpfiles, cache e hashes de integridade.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026
    Terminal de comandos representando parsing seguro com shlex no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shlex no Python: comandos e argumentos seguros

    Aprenda shlex no Python para separar comandos, tratar aspas, usar quote e join e reduzir riscos de injeção ao executar

    Ler mais

    Tempo de leitura: 7 minutos
    02/08/2026
    Banco de dados local representando persistência com shelve no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shelve no Python: persistência simples

    Aprenda shelve no Python para persistir objetos, atualizar dados mutáveis, evitar riscos de pickle e saber quando migrar para SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    01/08/2026