Запуск без исходных файлов 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 файлов? Является ли это желаемым поведением, означающим, что источник должен быть сохранен во всех ситуациях? Или я пропустил что-то глупое?

2 ответов


по данным ОПТОЗОС:

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

но:

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

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


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

по словам compileall doc:

-b
Write the byte-code files to their legacy locations and names, which may overwrite byte-code files created by another version of Python. The default is to write files to their PEP 3147 locations and names, which allows byte-code files from multiple versions of Python to coexist.

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