python 3从subdir导入

时间:2013-12-19 23:52:34

标签: python python-3.x

我的项目必须是可扩展的,我有很多脚本具有相同的界面,可以在线查找内容。在我使用__import__之前,但这不允许我将“插件”放在专用目录中:

root/
    main.py
    plugins/   
        [...]

所以我的问题是:有没有办法从该子目录单独导入模块?我猜想是importlib,但我迷失了python模块加载过程的工作原理......我想做的是这样的事情:

for pluginname in plugins:
    plugin = somekindofimport("plugins/{name}".format(name=pluginname))
    plugin.unififedinterface()

另外,作为一个附带问题,我试图实现可扩展性的方式是一种好方法吗?

我在python3.3上

1 个答案:

答案 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应用程序,以获得不同的想法。