动态加载python模块

时间:2009-06-04 14:59:26

标签: python dynamic python-import

在python中,如何在编程运行时动态地将模块添加到包中。

我希望能够从外部进程将模块添加到包目录中,并且能够在我的程序中使用这些新模块:

import package

def doSomething(name):
    pkg = __import__("package." + name)
    mod = getattr(pkg, name)
    mod.doSomething()

我该怎么做?

6 个答案:

答案 0 :(得分:55)

您的代码几乎是正确的。

请参阅__import__功能。

def doSomething(name):
    name = "package." + name
    mod = __import__(name, fromlist=[''])
    mod.doSomething()

答案 1 :(得分:22)

Bastien已经回答了这个问题,无论如何你可能会发现这个函数用来加载字典中子文件夹中的所有模块:

def loadModules():
    res = {}
    import os
    # check subfolders
    lst = os.listdir("services")
    dir = []
    for d in lst:
        s = os.path.abspath("services") + os.sep + d
        if os.path.isdir(s) and os.path.exists(s + os.sep + "__init__.py"):
            dir.append(d)
    # load the modules
    for d in dir:
        res[d] = __import__("services." + d, fromlist = ["*"])
    return res

另一个是通过第一个函数加载的一个模块中定义的类来实例化一个对象:

def getClassByName(module, className):
    if not module:
        if className.startswith("services."):
            className = className.split("services.")[1]
        l = className.split(".")
        m = __services__[l[0]]
        return getClassByName(m, ".".join(l[1:]))
    elif "." in className:
        l = className.split(".")
        m = getattr(module, l[0])
        return getClassByName(m, ".".join(l[1:]))
    else:
        return getattr(module, className)

使用这些功能的一种简单方法是:

mods = loadModules()
cls = getClassByName(mods["MyModule"], "submodule.filepy.Class")
obj = cls()

显然,您可以使用参数替换所有“services”子文件夹引用。

答案 2 :(得分:9)

Bastien回答的一个技巧...... __import__()函数返回包对象,而不是模块对象。如果您使用以下功能,它将从包中动态加载模块并返回模块,而不是包。

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

然后你可以这样做:

mod = my_import('package.' + name)
mod.doSomething()

答案 3 :(得分:9)

import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()

答案 4 :(得分:3)

要检测目录的更改,在Linux上,您可以使用pyinotifyhere是一个很好的工作示例);在Mac上,fsevents(通过Mac附带的PyObjC软件包);在Windows上,Directory Change Notifications通过win32api(或Python标准库ctypes模块)。 AFAIK,没有人将这些不同的方法整合到一个便携式包装中。 (当然,最糟糕的情况是,您可以回归到“低技术”方法,例如定期轮询,如Tim Golden's article,可能通过信号触及“来自外部进程的警报”等。) p>

获得通知以及新模块或修改模块的名称后,您在问题中显示的代码应该有效。

答案 5 :(得分:-1)

将模块目录添加到sys.path并使用正常的import语句。