Когда обновляются файлы .pyc?

92

Я понимаю, что файлы «.pyc» представляют собой скомпилированные версии файлов «.py» в виде обычного текста, созданные во время выполнения, чтобы программы работали быстрее. Однако я заметил несколько вещей:

  1. При модификации файлов "py" поведение программы меняется. Это указывает на то, что файлы "py" скомпилированы или, по крайней мере, проходят какой-то процесс хеширования или сравнивают временные метки, чтобы определить, нужно ли их перекомпилировать.
  2. После удаления всех файлов ".pyc" ( rm *.pyc) иногда поведение программы меняется. Это означает, что они не компилируются при обновлении файлов ".py".

Вопросы:

  • Как они решают, когда их компилировать?
  • Есть ли способ обеспечить более строгую проверку во время разработки?
Аарон Шиф
источник
15
Остерегайтесь удаления файлов .pyc с расширением rm *.pyc. Это не приведет к удалению файлов .pyc во вложенных папках. Использовать find . -name '*.pyc' -deleteвместо
Zags
6
Возможно, одно замечание по вашему вопросу: программа не работает быстрее, когда она читается из файла '.pyc' или '.pyo', чем когда она читается из файла '.py'; Единственное, что быстрее в файлах .pyc или .pyo, - это скорость, с которой они загружаются. ссылка
Мэгги 07
@maggie какая разница между временем загрузки и выполнения?
Дэниел Спрингер,
3
@Dani loading - это время, необходимое для чтения, а затем компиляции программы. Время выполнения - это время, когда программа фактически запускается, что происходит после загрузки. Если вы хотите быть техническим, типами времени являются время загрузки, время компиляции, время компоновки и время выполнения. Создание .pyc устраняет часть времени компиляции.
Эрик Клиен
@EricKlien благодарит человека
Дэниел Спрингер

Ответы:

81

Эти .pycфайлы создаются (и , возможно , переписаны) только тогда , когда этот файл питон импортируется какой - либо другой сценарий. Если вызывается импорт, Python проверяет, .pycне старше ли внутренняя метка времени файла, чем соответствующий .pyфайл. Если это так, он загружает .pyc; если это не так или если .pycон еще не существует, Python компилирует .pyфайл в .pycи загружает его.

Что вы имеете в виду под «более строгой проверкой»?

Дэйв Ученый
источник
3
Я могу исправить проблемы с rm *.pyc. Я знаю, что если я принудительно воссоздаю все файлы, некоторые проблемы будут исправлены, что означает, что файлы не перекомпилируются сами по себе. Я полагаю, что если они используют временные метки, то нет способа сделать это поведение более строгим, но проблема все еще сохраняется.
Аарон Шиф
14
Это не совсем так. Метки времени не обязательно должны совпадать (и обычно это не так). В .pyc«метка времени ДОЛЖНО быть старше , чем соответствующий .py» метки времени s , чтобы вызвать перекомпиляции.
Тим Пицкер
4
@Aaron, возможно, вы меняете файлы .py и в процессе делаете их старше (например, копируя их из другого каталога, используя операцию, которая сохраняет «время модификации»)?
greggo
1
@greggo, я использую git и обновляюсь из репозитория, так что да, в каком-то смысле. Это могло сделать это. Спасибо.
Аарон Шиф
1
Хорошо знать. Как насчет того, чтобы исправить свой ответ?
Петр Доброгост
31

Файлы .pyc, создаваемые при импорте соответствующих элементов кода, и обновляются, если соответствующие файлы кода были обновлены. Если файлы .pyc удалены, они будут автоматически восстановлены. Однако они не удаляются автоматически при удалении соответствующих файлов кода.

Это может вызвать некоторые действительно забавные ошибки во время рефакторинга на уровне файлов.

Прежде всего, вы можете отправить код, который работает только на вашем компьютере и ни на каком другом. Если у вас есть висящие ссылки на удаленные вами файлы, они все равно будут работать локально, если вы не удалите вручную соответствующие файлы .pyc, поскольку файлы .pyc можно использовать при импорте. Это усугубляется тем фактом, что правильно настроенная система контроля версий будет отправлять только файлы .py в центральный репозиторий, а не файлы .pyc, а это означает, что ваш код может пройти «тест на импорт» (все ли импортируются правильно) нормально, а не работать на чужом компьютере.

Во-вторых, вы можете столкнуться с ужасными ошибками, если превратите пакеты в модули. Когда вы конвертируете пакет (папку с __init__.pyфайлом) в модуль (файл .py), файлы .pyc, которые когда-то представляли этот пакет, остаются. В частности, __init__.pycосталось. Итак, если у вас есть пакет foo с каким-то кодом, который не имеет значения, то позже удалите этот пакет и создайте файл foo.py с некоторой функцией def bar(): passи запустите:

from foo import bar

Вы получаете:

ImportError: cannot import name bar

потому что python все еще использует старые файлы .pyc из пакета foo, ни один из которых не определяет bar. Это может быть особенно проблематично на веб-сервере, где полностью работающий код может сломаться из-за файлов .pyc.

В результате обеих этих причин (и, возможно, других) ваш код развертывания и тестовый код должны удалить файлы .pyc, например, со следующей строкой bash:

find . -name '*.pyc' -delete

Кроме того, начиная с python 2.6, вы можете запускать python с -Bфлагом, чтобы не использовать файлы .pyc. См. Как избежать файлов .pyc? Больше подробностей.

См. Также: Как удалить все файлы .pyc из проекта?

Загс
источник
«При конвертации модуля (папки с __init__.pyфайлом) ...». Это будет пакет, а не модуль.
Роберт Дэвид Грант
2
В частности, __init__.pycосталось. - Как придешь? Поскольку пакет - это каталог, то удаление пакета означает удаление каталога, поэтому файлов не осталось…
Петр Доброгост
3
@PiotrDobrogost Правильно управляемый контроль версий подразумевает отсутствие проверки ваших файлов pyc в исходном коде. Таким образом, хотя вы можете удалить папку, включая файлы pyc, в своей локальной копии, она не будет удалена для кого-то еще, кто выполняет git pull. Это может привести к сбою вашего сервера, если ваше развертывание также включает git pull.
Zags
Есть много причин не доверять своей среде разработки как репрезентативной для того, где будет развернут ваш код. Эта .pycпроблема также является одной из причин: скрытые зависимости от ОС и уровней исправлений утилит, .soфайлов , файлов конфигурации, других библиотек Python (если вы не работаете в виртуальном окружении), непонятных переменных env ... список можно продолжать. Чтобы быть тщательным и найти все подобные проблемы, вам нужно сделать чистую копию вашего кода в репозитории git или опубликовать как пакет на сервере в стиле PyPi и выполнить полное клонирование или настройку на новой виртуальной машине. Некоторые из этих потенциальных проблем делают эту .pycпроблему бледной по сравнению с этим.
Крис Джонсон