Quando os arquivos .pyc são atualizados?

91

Eu entendo que os arquivos ".pyc" são versões compiladas dos arquivos ".py" de texto simples, criados em tempo de execução para fazer os programas rodarem mais rápido. No entanto, observei algumas coisas:

  1. Após a modificação dos arquivos "py", o comportamento do programa muda. Isso indica que os arquivos "py" são compilados ou, pelo menos, passam por algum tipo de processo de hash ou comparam os registros de data e hora para saber se devem ou não ser recompilados.
  2. Ao excluir todos os arquivos ".pyc" ( rm *.pyc), às vezes o comportamento do programa muda. O que indicaria que eles não estão sendo compilados na atualização de ".py" s.

Questões:

  • Como eles decidem quando serão compilados?
  • Existe uma maneira de garantir que eles tenham uma verificação mais rigorosa durante o desenvolvimento?
Aaron Schif
fonte
14
Cuidado ao excluir arquivos .pyc com rm *.pyc. Isso não excluirá arquivos .pyc em pastas aninhadas. Use em seu find . -name '*.pyc' -deletelugar
Zags
6
Talvez uma observação sobre a sua pergunta: um programa não é executado mais rápido quando é lido de um arquivo '.pyc' ou '.pyo' do que quando é lido de um arquivo '.py'; a única coisa que é mais rápida nos arquivos '.pyc' ou '.pyo' é a velocidade com que são carregados. link
maggie
@maggie qual é a diferença entre o tempo de carregamento e execução?
Daniel Springer
3
O carregamento @Dani é o tempo que leva para ler e compilar o programa. O tempo de execução é quando o programa está realmente sendo executado, o que ocorre após o carregamento. Se você quiser ser técnico, os tipos de tempo são tempo de carregamento, tempo de compilação, tempo de link e tempo de execução. Fazer um .pyc elimina a parte do tempo de compilação.
Eric Klien
@EricKlien obrigado homem
Daniel Springer

Respostas:

78

Os .pycarquivos são criados (e possivelmente sobrescritos) apenas quando o arquivo Python é importado por algum outro script. Se a importação for chamada, o Python verificará se o .pyccarimbo de data / hora interno do arquivo não é mais antigo que o .pyarquivo correspondente . Se for, ele carrega o .pyc; se não for ou se .pycainda não existir, o Python compila o .pyarquivo em um .pyce o carrega.

O que você quer dizer com "verificação mais rigorosa"?

DaveTheScientist
fonte
3
Consigo resolver problemas com rm *.pyc. Eu sei que se eu forçar a recriação de todos os arquivos, alguns problemas serão corrigidos, indicando que os arquivos não estão sendo recompilados por si próprios. Suponho que, se eles usarem os carimbos de data / hora, não haverá como tornar esse comportamento mais rígido, mas o problema ainda persiste.
Aaron Schif,
13
isto não está correto. Os carimbos de data / hora não precisam corresponder (e geralmente não correspondem). O .pyccarimbo de data / hora de deve ser anterior ao .pycarimbo de data / hora correspondente para acionar uma recompilação.
Tim Pietzcker,
4
@Aaron, você está possivelmente alterando os arquivos .py e, no processo, tornando-os mais antigos (por exemplo, copiando-os de outro diretório, usando uma operação que preserva o 'tempo de modificação')?
greggo
1
@greggo, estou usando git e atualizando de um repositório, então sim, de certa forma. Isso poderia funcionar. Obrigado.
Aaron Schif,
1
Bom saber. Que tal corrigir sua resposta então?
Piotr Dobrogost
29

Arquivos .pyc gerados sempre que os elementos de código correspondentes são importados e atualizados se os arquivos de código correspondentes foram atualizados. Se os arquivos .pyc forem excluídos, eles serão regenerados automaticamente. No entanto, eles não são excluídos automaticamente quando os arquivos de código correspondentes são excluídos.

Isso pode causar alguns erros realmente divertidos durante os refatores em nível de arquivo.

Em primeiro lugar, você pode acabar empurrando um código que só funciona na sua máquina e em mais ninguém. Se você tiver referências pendentes a arquivos excluídos, eles ainda funcionarão localmente se você não excluir manualmente os arquivos .pyc relevantes, porque os arquivos .pyc podem ser usados ​​nas importações. Isso é agravado pelo fato de que um sistema de controle de versão configurado corretamente irá apenas enviar arquivos .py para o repositório central, não arquivos .pyc, o que significa que seu código pode passar no "teste de importação" (tudo importa bem) muito bem e não trabalhar no computador de outra pessoa.

Em segundo lugar, você pode ter alguns bugs terríveis se transformar pacotes em módulos. Quando você converte um pacote (uma pasta com um __init__.pyarquivo) em um módulo (um arquivo .py), os arquivos .pyc que antes representavam esse pacote permanecem. Em particular, os __init__.pycrestos mortais. Então, se você tiver o pacote foo com algum código que não importa, então exclua esse pacote e crie um arquivo foo.py com alguma função def bar(): passe execute:

from foo import bar

você obtém:

ImportError: cannot import name bar

porque o python ainda está usando os arquivos .pyc antigos do pacote foo, nenhum dos quais define bar. Isso pode ser especialmente problemático em um servidor da web, onde o código em pleno funcionamento pode quebrar por causa de arquivos .pyc.

Como resultado de ambos os motivos (e possivelmente outros), o código de implantação e o código de teste devem excluir arquivos .pyc, como a seguinte linha de bash:

find . -name '*.pyc' -delete

Além disso, a partir do python 2.6, você pode executar o python com o -Bsinalizador para não usar arquivos .pyc. Consulte Como evitar arquivos .pyc? para mais detalhes.

Consulte também: Como removo todos os arquivos .pyc de um projeto?

Zags
fonte
"Quando você converte um módulo (uma pasta com um __init__.pyarquivo) ...". Isso seria um pacote, não um módulo.
Robert David Grant
2
Em particular, os __init__.pycrestos mortais. - Por quê? Como um pacote é um diretório, deletar um pacote significa deletar diretório, portanto, não há arquivos restantes ...
Piotr Dobrogost
3
@PiotrDobrogost O controle de origem gerenciado corretamente envolve a não verificação de seus arquivos pyc na origem. Portanto, embora você possa excluir a pasta, incluindo os arquivos pyc, em sua cópia local, ela não será excluída para outra pessoa que fizer um git pull. Isso pode travar seu servidor se sua implantação envolver um git pull também.
Zags
Há muitos motivos para não confiar que seu ambiente de desenvolvimento seja representativo de onde seu código será implantado. Esse .pycproblema também é um motivo: dependências ocultas no sistema operacional e níveis de patch de utilitário, .soarquivos , arquivos de configuração, outras bibliotecas Python (se você não estiver executando em um ambiente virtual), vars env obscuros ... a lista continua. Para ser completo e encontrar todos esses problemas, você precisa fazer uma cópia limpa do seu código em um repositório git ou publicar como um pacote em um servidor estilo PyPi e fazer uma clonagem completa ou configuração em uma nova VM. Alguns desses problemas potenciais tornam esse .pycproblema insignificante em comparação.
Chris Johnson