我知道“ .pyc”文件是纯文本“ .py”文件的编译版本,是在运行时创建的,以使程序运行更快。但是我观察到了一些事情:
- 修改“ py”文件后,程序行为会更改。这表明“ py”文件已编译或至少经过某种哈希处理或比较时间戳,以便确定是否应重新编译它们。
- 删除所有“ .pyc”文件(
rm *.pyc
)后,有时程序行为也会改变。这表明它们不是在更新“ .py”时被编译的。
问题:
- 他们如何决定何时编译?
- 有没有办法确保他们在开发过程中进行更严格的检查?
我知道“ .pyc”文件是纯文本“ .py”文件的编译版本,是在运行时创建的,以使程序运行更快。但是我观察到了一些事情:
rm *.pyc
)后,有时程序行为也会改变。这表明它们不是在更新“ .py”时被编译的。问题:
Answers:
该.pyc
文件被创建(并可能覆盖)仅当蟒蛇文件是否已被其他脚本导入。如果调用了导入,Python将检查.pyc
文件的内部时间戳是否不早于相应的.py
文件。如果是,它将加载.pyc
;。如果.pyc
不存在或尚不存在,Python 会将.py
文件编译为.pyc
并加载。
“严格检查”是什么意思?
rm *.pyc
。我知道如果我强制重新创建所有文件,则某些问题已修复,这表明这些文件本身并未被重新编译。我想如果他们确实使用时间戳,则没有办法使这种行为更严格,但是问题仍然存在。
.pyc
的时间戳必须是年龄较大的比相应.py
的时间戳来触发重新编译。
每当导入相应的代码元素时都会生成.pyc文件,如果相应的代码文件已更新,则将更新.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仍在使用foo包中的旧.pyc文件,但都没有定义bar。这在Web服务器上尤其成问题,在Web服务器上,.pyc文件可能会破坏所有正常运行的代码。
由于这两个原因(可能还有其他两个原因),您的部署代码和测试代码应删除.pyc文件,例如使用以下bash行:
find . -name '*.pyc' -delete
另外,从python 2.6开始,您可以运行带有-B
标记的python,以不使用.pyc文件。请参阅如何避免.pyc文件?更多细节。
另请参阅:如何从项目中删除所有.pyc文件?
__init__.py
文件夹)时...”。那将是一个包装,而不是一个模块。
__init__.pyc
遗骸。- 怎么会?由于软件包是目录,因此删除软件包意味着删除目录,因此没有文件了……
.pyc
问题也是一个原因,原因是:对OS和实用程序补丁程序级别,.so
文件,配置文件,其他Python库(如果您不在虚拟环境中运行)的隐藏依赖性,模糊的环境变量...等等。为了彻底查找所有此类问题,您需要在git repo中制作代码的完整副本,或将其作为软件包发布到PyPi样式服务器中,然后在新的VM上进行完整的克隆或设置。.pyc
相比之下,其中一些潜在问题使此问题显得苍白。
rm *.pyc
。这不会删除嵌套文件夹中的.pyc文件。使用find . -name '*.pyc' -delete
替代