导入不带.py扩展名的Python模块
我有一个文件叫做 foobar(没有 .py 后缀)。在同一个文件夹里,我还有另一个 Python 文件想要导入它:
import foobar
但是这只有在我把文件重命名为 foobar.py 的时候才有效。有没有办法导入一个没有 .py 后缀的 Python 模块呢?
更新:这个文件没有后缀是因为我也把它当作独立脚本使用,我不想在运行它的时候还要输入 .py 后缀。
更新2:我会选择下面提到的符号链接解决方案。
7 个回答
就像其他人提到的,你可以使用 imp.load_source,但这样会让你的代码变得不太容易理解。我只建议在你需要导入那些在运行时才知道名字或路径的模块时使用它。
你为什么不想使用 .py 后缀呢?最常见的原因是因为这个 Python 脚本也作为可执行文件运行,但你仍然希望其他模块能够导入它。如果是这样的话,把功能放到一个名字相似的 .py 文件中可能会更好,然后用 foobar
来作为一个包装器。
这里有一个适用于Python 3.4及以上版本的解决方案:
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
spec = spec_from_loader("foobar", SourceFileLoader("foobar", "/path/to/foobar"))
foobar = module_from_spec(spec)
spec.loader.exec_module(foobar)
使用 spec_from_loader
,并明确指定一个 SourceFileLoader
,可以强制程序将文件作为源代码加载,而不需要根据文件的后缀名来判断文件类型。这意味着即使文件没有在 importlib.machinery.SOURCE_SUFFIXES
中列出,你也可以加载这个文件。
如果你想在第一次加载后继续通过名称导入这个文件,可以将模块添加到 sys.modules
中:
sys.modules['foobar'] = foobar
你可以在我维护的一个工具库中找到这个函数的实现,叫做 haggis。 haggis.load.load_module
提供了将模块添加到 sys.modules
、设置自定义名称以及向代码的命名空间注入变量的选项。
你可以使用 imp.load_source
这个函数(来自 imp
模块),来从指定的文件路径动态加载一个模块。
import imp
foobar = imp.load_source('foobar', '/path/to/foobar')
这个 SO讨论 也展示了一些有趣的选择。