在Python 3.4中不使用Python源文件运行



我试图运行一个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文件?这是期望的行为吗?这意味着在所有情况下都必须保留源文件?还是我错过了什么愚蠢的东西?

没有足够的声誉来给BrenBarn的回答添加评论。这是一些补充。

根据compileall文档:

- b

将字节码文件写入其遗留位置和名称,这可能会覆盖由其他版本的Python创建的字节码文件。默认是将文件写入其PEP 3147位置和名称,这允许来自多个Python版本的字节码文件共存。

因此您可以运行python -m compileall -b .来递归地编译此目录下的所有代码文件

根据PEP:

有可能foo.py文件以某种方式被删除了,而缓存的pyc文件仍然在文件系统上。如果__pycache__/foo.<magic>.pyc文件存在,但用于创建它的foo.py文件不存在,Python将在被要求导入foo时引发ImportError。换句话说,Python不会从缓存目录导入pyc文件,除非源文件存在。

但:

为了继续支持无源发行版,如果源文件丢失,Python将导入一个单独的pyc文件,如果它位于源文件所在的位置。

所以看起来__pycache__和无源发行版是相互排斥的。如果您想要删除源代码,您需要将.pyc文件移到源代码所在的目录中。

最新更新