Подтвердить что ты не робот

Запуск без исходных файлов Python в Python 3.4

Я пытаюсь запустить приложение Python, не поддерживая исходные файлы .py и полагаясь только на файлы .pyc. Тем не менее, я получаю ошибки импорта, когда я удаляю исходные файлы .py. Эта функциональность работает в Python 2.7, но не в 3.4 (с новой структурой __pycache__).

Вот пример структуры каталогов:

package/
  __init__.py
  module.py

Python 2.7

Сначала посмотрим, что произойдет, когда я использую Python 2.7 (это желаемое поведение)

$ python2 -c "from package import module"
$ find package -name "*.py" -delete
$ python2 -c "from package import module"

Все хорошо, и ошибок не возникает. Структура каталогов после этого будет выглядеть так: файлы .pyc вдоль исходных файлов .py:

package/
  __init__.pyc
  module.pyc

Python 3.4

Теперь сделаем то же самое с Python 3.4, начиная с нашей исходной структуры каталога снова

$ python3 -c "from package import module"
$ find package -name "*.py" -delete
$ python3 -c "from package import module"
 Traceback (most recent call last):
   File "<string>", line 1, in <module>
 ImportError: cannot import name 'module'

Ух, он не может импортировать модуль. Интересно, что я все еще мог безопасно запустить python3 -c "import package" на этом этапе, но он не может захватить какие-либо модули оттуда. На данный момент структура каталогов выглядит немного иначе, чем в версии 2.7, в частности:

package/
  __pycache__/
      __init__.cpython-34.pyc
      module.cpython-34.pyc

Итак, вопрос заключается в следующем: почему Python 3.4 не может импортировать/выполнять правильно только для файлов .pyc? Является ли это желательным поведением, а это значит, что источник должен поддерживаться во всех ситуациях? Или мне не хватает чего-то глупого?

4b9b3361

Ответ 1

Согласно PEP:

Возможно, файл foo.py каким-то образом удален, оставив файл кэшированного pyc все еще в файловой системе. Если файл __pycache__/foo.<magic>.pyc существует, но файл foo.py, используемый для его создания, нет, Python будет поднимать ImportError, когда его попросят импортировать foo. Другими словами, Python не будет импортировать файл pyc из каталога кэша, если исходный файл не существует.

Но:

Чтобы продолжать поддерживать дистрибутивы без источника, хотя, если исходный файл отсутствует, Python будет импортировать одиночный файл pyc, если он живет там, где был бы исходный файл.

Таким образом, кажется, что __pycache__ и бесполезные дистрибутивы являются взаимоисключающими. Если вы хотите удалить источник, вам нужно переместить файлы .pyc в каталог, в котором был бы источник.

Ответ 2

Нет достаточной репутации, чтобы добавить комментарий к ответу BrenBarn. Итак, вот некоторые дополнения.

Согласно compileall документу:

-b

Запишите файлы кода byte- в их прежние места и имена, которые могут перезаписать файлы кода byte-, созданные другой версией Python. По умолчанию файлы записываются в их местоположения и имена PEP 3147, что позволяет сосуществовать кодовым файлам byte- из нескольких версий Python.

Таким образом, вы можете запустить python -m compileall -b . для рекурсивной компиляции всех файлов кода в этом каталоге.