动态加载python模块

51 python dynamic python-import

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

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

import package

def doSomething(name):
    pkg = __import__("package." + name)
    mod = getattr(pkg, name)
    mod.doSomething()
Run Code Online (Sandbox Code Playgroud)

我该怎么做呢?

S.L*_*ott 55

你的代码几乎是正确的.

__import__功能.

def doSomething(name):
    name = "package." + name
    mod = __import__(name, fromlist=[''])
    mod.doSomething()
Run Code Online (Sandbox Code Playgroud)

  • __import__返回模块,因此您可以执行"mod = __import __(name)"而不必在sys.modules中查找它. (4认同)
  • 编辑使用fromlist参数.在fromlist中传递一些东西(任何东西)会导致__import__直接返回你想要的模块. (3认同)
  • 对 Brian 评论的澄清... __import__ 返回包,而不是模块。因此,您需要在 sys.modules 中查找模块,或者使用我的技术(在另一个答案中列出)从包中获取模块。 (2认同)

Gio*_*rdi 23

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
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

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

mods = loadModules()
cls = getClassByName(mods["MyModule"], "submodule.filepy.Class")
obj = cls()
Run Code Online (Sandbox Code Playgroud)

显然,您可以使用参数替换所有"服务"子文件夹引用.


小智 13

import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
Run Code Online (Sandbox Code Playgroud)


Cli*_*ler 9

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

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

然后你可以这样做:

mod = my_import('package.' + name)
mod.doSomething()
Run Code Online (Sandbox Code Playgroud)


Aar*_*lla -1

添加模块目录sys.path并使用普通import语句。

  • 这并不能解决问题。模块名称由用户指定,正常导入似乎不需要字符串。此外,它不会检测“新”模块。 (4认同)