我试图运行一个Python应用程序,而不保留.py
源文件,只依赖于.pyc
编译文件。但是,当我删除.py
源文件时,我正在获得导入错误。此功能在Python 2.7中工作,但在3.4中不工作(使用新的__pycache__
结构)。
Python 2.7package/ __init__.py module.py
首先让我们看看当我使用Python 2.7时会发生什么(这是期望的行为)
$ python2 -c "from package import module"
$ find package -name "*.py" -delete
$ python2 -c "from package import module"
一切正常,不会抛出错误。这样做之后的目录结构看起来像这样,.pyc
文件和原始.py
文件在一起:
Python 3.4package/ __init__.pyc module.pyc
现在,让我们在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文件移到源代码所在的目录中。