动态加载Python模块

4 投票
7 回答
19800 浏览
提问于 2025-04-15 11:11

我正在尝试动态加载我创建的模块。

现在这样做是可以的:

import structures.index

但是如果我尝试通过动态导入来做同样的事情,就会失败。

struct = __import__("structures.index")

出现的错误是:

Error ('No module named structures.index',)

有人知道为什么吗?


编辑:当使用完整作用域时(这似乎有点有效):

struct = __import__("neoform.structures.index")

这没有抛出任何错误,但它没有加载索引模块,而是加载了“neoform”模块。

“struct”的结果是:

<module 'neoform' from '/neoform/__init__.py'>

另外,作为一个附带问题,我该如何在动态加载的模块中实例化一个类呢?(假设所有模块都包含一个公共的类名)。

编辑:解决方案:(感谢 coonj 和 Rick)这就是有效的做法。不知道为什么(还没搞明白),但 fromlist 必须是某个“东西”,显然,因为当我把字母“a”作为值时它就有效了(这很奇怪,因为文件里只有一个类)。

def get_struct_module(self, name):
    try:
        return = __import__("neoform.structures." + name, fromlist='*')
    except ImportError, e:
        self.out.add("Could not load struct: neoform.structure." + name + "\n\n" + "Error " + str(e.args))

7 个回答

3

使用完整的范围("neoform.structures.index")来配合这个辅助方法。

def import_module(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

module = import_module("neoform.structures.index")
# do stuff with module
4

要导入子模块,你需要在 __import__()fromlist 参数中指定它们。
比如,下面这段代码的意思是:

import structures.index

等价于:

structures = __import__('structures', fromlist=['index'])

在映射中做这个就有点复杂了...

import mod1.index
import mod2.index
import mod3.index

对于这些导入,你需要定义一个新函数来从每个模块中获取 index 子模块:

def getIndexMods(mod_names):
  mod_list = map(lambda x: __import__(x, fromlist='index'))
  index_mods = [mod.index for mod in mod_list]
  return index_mods

现在,你可以这样做来获取所有 index 模块的引用:

index_mods = getIndexMods(['mod1', 'mod2', 'mod3'])

另外,如果你想获取一些不是叫 'index' 的子模块,你可以这样做:

mod1, mod2, mod3 = map(lambda x,y: __import__(x, fromlist=y), 
  ['mod1', 'mod2', 'mod3'], ['index1', 'index2', 'index3'])
12

我不太明白“它失败了”是什么意思,所以我只想提一下,__import__('structures.index') 其实是可以工作的,但它不会把模块名放在当前的作用域里。要做到这一点(然后使用动态导入的模块中的一个类),你需要这样做:

structures = __import__('structures.index')
structures.index.SomeClass(...)

关于 __import__ 的详细信息可以在 这里 找到。

编辑:(基于问题的修改)

要导入 neoform.structures.index 并返回 index 模块,你可以这样做:

structures = __import__('neoform.structures.index', 
                        fromlist=['does not in fact matter what goes here!'])

所以如果你有一个包名的列表 packages,你可以导入它们的 index 模块,并为每个模块实例化一个 MyClass 类,使用以下代码:

modules = [ __import__('neoform.%s.index' % pkg, fromlist=['a']) 
            for pkg in packages ]
objects = [ m.MyClass() for m in modules ]

撰写回答