从动态导入模块中根据字符串名称动态实例化类?

266 投票
10 回答
236499 浏览
提问于 2025-04-16 10:44

在Python中,我需要根据一个字符串中的类名来创建某个类的实例,但这个类是在一个动态导入的模块里。下面是一个例子:

加载器类的脚本:

import sys
class loader:
  def __init__(self, module_name, class_name): # both args are strings
    try:
      __import__(module_name)
      modul = sys.modules[module_name]
      instance = modul.class_name() # obviously this doesn't works, here is my main problem!
    except ImportError:
       # manage import error

某个动态加载模块的脚本:

class myName:
  # etc...

我使用这种方式来让任何动态加载的模块按照预先定义好的行为被加载器类使用...

10 个回答

22

复制粘贴代码片段:

import importlib
def str_to_class(module_name, class_name):
    """Return a class instance from a string reference"""
    try:
        module_ = importlib.import_module(module_name)
        try:
            class_ = getattr(module_, class_name)()
        except AttributeError:
            logging.error('Class does not exist')
    except ImportError:
        logging.error('Module does not exist')
    return class_ or None
176

简要说明

使用 importlib.import_module 来导入根模块,然后通过 getattr 函数根据类名加载这个类:

# Standard import
import importlib
# Load "module.submodule.MyClass"
MyClass = getattr(importlib.import_module("module.submodule"), "MyClass")
# Instantiate the class (pass arguments to the constructor, if needed)
instance = MyClass()

详细解释

你可能不想用 __import__ 来动态导入模块,因为它不支持导入子模块:

>>> mod = __import__("os.path")
>>> mod.join
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'join'

这里是Python文档对 __import__ 的说明:

注意:这是一个高级函数,在日常的Python编程中并不需要,和 importlib.import_module() 不同。

相反,应该使用标准的 importlib 模块来根据名称动态导入模块。然后,你可以用 getattr 根据类名实例化一个类:

import importlib
my_module = importlib.import_module("module.submodule")
MyClass = getattr(my_module, "MyClass")
instance = MyClass()

你也可以这样写:

import importlib
module_name, class_name = "module.submodule.MyClass".rsplit(".", 1)
MyClass = getattr(importlib.import_module(module_name), class_name)
instance = MyClass()

这段代码在Python 2.7及以上版本(包括Python 3)都是有效的。

368

你可以使用 getattr

getattr(module, class_name)

来访问这个类。更完整的代码如下:

module = __import__(module_name)
class_ = getattr(module, class_name)
instance = class_()

正如下面提到的 内容,我们可以使用 importlib

import importlib
module = importlib.import_module(module_name)
class_ = getattr(module, class_name)
instance = class_()

撰写回答