强制Python在从文件路径动态加载模块时忽略pyc文件

4
我需要在运行时通过文件路径(例如“/some/path/to/module.py”)导入Python模块,并忽略任何存在的“.pyc”文件。
这个之前的问题建议使用imp.load_module作为解决方案,但是这种方法似乎也会使用已经存在的.pyc版本。

importme.py

SOME_SETTING = 4

main.py:

import imp
if __name__ == '__main__':
    name = 'importme'
    openfile, pathname, description = imp.find_module(name)
    module = imp.load_module(name, openfile, pathname, description)
    openfile.close()
    print module

在执行两次后,第一次调用后将使用 .pyc 文件:
$ python main.py 
<module 'importme' from '/Users/dbryant/temp/pyc/importme.py'>

$ python main.py 
<module 'importme' from '/Users/dbryant/temp/pyc/importme.pyc'>

很遗憾,imp.load_source 有相同的行为(来自文档):

请注意,如果存在一个与给定源文件匹配的正确的编译字节文件(带有后缀 .pyc 或 .pyo),将使用它而不是解析给定源文件。

使每个包含脚本的目录都只读是我所知道的唯一解决方案(首先防止生成 .pyc 文件),但如果可能的话,我宁愿避免这样做。

(注:使用 python 2.7)


1
你为什么想要防止使用pyc文件?只有当py和pyc文件相同时,才会使用pyc文件。如果你修改了py文件,它将重新编译pyc文件。 - Falmarri
@Falmarri 这个问题比较复杂。它与不同类型的机器访问相同的Python文件有关,它们似乎会生成不兼容的字节编译版本的相同源代码(导致机器B无法动态导入由机器A生成的pyc模块)。是的,所有机器都使用解释器二进制文件。 - awesomo
唯一不同的机器会编写不同字节码是因为它们运行不同版本的解释器。 - limscoder
3个回答

2

load_source 对我来说是正确的,即

dir, name = os.path.split(path)
mod = imp.load_source(name, path)

即使存在 .pyc 文件,也会使用 .py 变体 - 在 Python3 中该文件名以 .py 结尾。显然的解决方案是在加载文件之前删除所有的 .pyc 文件 - 但如果运行多个程序实例,则竞争条件可能会成为问题。

另一种可能性:如果我没记错的话,可以让 Python 解释内存中的文件 - 即使用正常的文件 API 加载文件,然后编译内存中的变体。类似这样的代码:

path = "some Filepath.py"
with open(path, "r", encoding="utf-8") as file:
    data = file.read()
exec(compile(data, "<string>", "exec")) # fair use of exec, that's a first!

不错,我甚至没有考虑过执行设置文件/模块内容。这对我来说也是可行的解决方案。 - awesomo

0

您可以将包含 .py 文件的目录标记为只读。


是的,我知道(见问题底部),但这并没有真正解决问题,而且非常不方便,因为我仍然需要写入包含日志、输出等的目录。 - awesomo
我不知道你的具体情况是什么,但通常我会尽量避免将数据写入包含代码的同一目录。 - limscoder
我原则上同意,但在这种情况下Python的设置文件模糊了数据和代码之间的界限(比如在Django中非常常见)。 - awesomo

0
使用包含Python源代码的zip文件怎么样?
import sys
sys.path.insert("package.zip")

有趣,但并不适用于我的使用情况。我动态加载的模块是设置文件,需要易于人类阅读和编辑。 - awesomo
2
您还可以考虑使用PYTHONDONTWRITEBYTECODE环境变量。 - ILYA Khlopotov
好主意。那也可以,但是唯一会引起问题的是使用imp动态加载的.pyc文件,我希望在其他情况下仍然能够使用字节码版本。 - awesomo
3
可以使用 sys.dont_write_bytecode 设置环境变量,导入模块后将字节码设置更改回原样,以实现此操作。 - Sanjamal
@Sanjamal 谢谢,如果你的建议有效的话,那对我来说就足够了。我会进行测试。 - awesomo
@Sanjamal,你的解决方案非常完美。 如果你把它提交为答案,我很乐意接受它。 - awesomo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接