dynamic加载python模块

在Python中,如何在编程运行时dynamic地将模块添加到包中。

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

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

我如何做到这一点?

你的代码几乎是正确的。

请参阅__import__函数。

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

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) 

一个简单的方法来使用这些function是这样的:

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

显然你可以用参数replace所有的“服务”子文件夹引用。

与Bastien的答案一个技巧… __import__()函数返回包对象,而不是模块对象。 如果使用下面的函数,它将dynamic地从包中加载模块,并返回模块,而不是包。

 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() 

要检测对目录的更改,在Linux上,可以使用pyinotify ( 这里是一个很好的工作示例)。 在Mac上, fsevents (通过Mac 附带的PyObjC软件包); 在Windows上,通过win32api (或Python标准库ctypes模块)进行目录更改通知 。 AFAIK,没有人把这些不同的方法结合到一个便携包中。 (当然,最糟糕的情况是,你可以回到“低技术”的方式,比如定期轮询, Tim Golden的文章 ,也许是通过一个信号等等一些“来自外部过程的警报”)。

一旦你有通知和新的或修改模块的名称,你在问题中显示的代码应该工作。

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

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