我的项目必须是可扩展的,我有很多脚本具有相同的界面,可以在线查找内容。在我使用__import__
之前,但这不允许我将“插件”放在专用目录中:
root/
main.py
plugins/
[...]
所以我的问题是:有没有办法从该子目录单独导入模块?我猜想是importlib,但我迷失了python模块加载过程的工作原理......我想做的是这样的事情:
for pluginname in plugins:
plugin = somekindofimport("plugins/{name}".format(name=pluginname))
plugin.unififedinterface()
另外,作为一个附带问题,我试图实现可扩展性的方式是一种好方法吗?
我在python3.3上
答案 0 :(得分:3)
不再考虑路径名并开始考虑包装。请阅读教程中的Packages,如果您需要更多详细信息,请参阅The import system。
但基本的想法是:
创建文件名plugins/__init__.py
。它可以是空的;这足以将plugins
变成包。这意味着您可以使用以下命令从该包导入模块:
import plugins.plugin
那么,你如何动态地做到这一点?这就是importlib
的用途。 (你也可以在这里使用__import__
,但它不太灵活,在非平凡的情况下可读性较差,所以除非你需要3.3之前的兼容性,否则不要。)
plugin = importlib.import_module('plugins.{name}'.format(name=pluginname))
import plugins
获取软件包可能更干净,然后使用该软件包中的相对导入,如import_module
文档中的示例所示。
这也意味着Python负责.pyc创建和缓存等。
这意味着您以后可以将plugins
扩展为“命名空间包”,可以将其分为多个目录,例如/usr/share/myapp/plugins
用于库存插件,/etc/myapp/plugins
用于站点插件和~/myapp/plugins
用于特定于用户的插件。
如果你真的,真的想从一个不是包的目录导入,你可以创建一个模块加载器并使用它,但这是一大堆工作,没有实际的好处。 (3.3实际上并不那么难(SourceLoader
和朋友会为你完成大部分工作),但你会发现几乎没有例子可以指导你;相反,你会发现2.6-的例子3.2方式,或2.0-2.5方式,两者都很难。)另外,这意味着如果有人创建了一个名为gzip
的插件,你最终可能会阻止带插件的stdlib gzip
模块。 (如果gzip
插件尝试使用gzip
stdlib模块,那会特别有趣,因为它可能会......)如果插件最终被命名为plugins.gzip
,则没有问题。
另外,作为一个附带问题,我试图实现可扩展性的方式是一种好方法吗?
只要您只想支持3.3+,是的,我认为这是一个很好的解决方案。
在3.3之前,使用插件包进行插件的问题更多。人们已经提出了各种不同的插件系统 - 在一种情况下,动态创建模块对象和execfile
。如果您需要处理这个问题,我建议您使用插件(例如,MusicBrainz Picard)查看现有的Python应用程序,以获得不同的想法。