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

问题:从动态导入的模块中的类的字符串名称动态实例化?

在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...

我使用这种安排使dyn-loaded-modules中的某些预定义行为使加载程序类使用任何动态加载的模块…

In python, I have to instantiate certain class, knowing its name in a string, but this class ‘lives’ in a dynamically imported module. An example follows:

loader-class script:

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

some-dynamically-loaded-module script:

class myName:
  # etc...

I use this arrangement to make any dynamically-loaded-module to be used by the loader-class following certain predefined behaviours in the dyn-loaded-modules…


回答 0

您可以使用getattr

getattr(module, class_name)

访问类。更完整的代码:

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

如前所述下面,我们可以使用导入库

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

You can use getattr

getattr(module, class_name)

to access the class. More complete code:

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

As mentioned below, we may use importlib

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

回答 1

tl; dr

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)中有效。

tl;dr

Import the root module with importlib.import_module and load the class by its name using getattr function:

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

explanations

You probably don’t want to use __import__ to dynamically import a module by name, as it does not allow you to import submodules:

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

Here is what the python doc says about __import__:

Note: This is an advanced function that is not needed in everyday Python programming, unlike importlib.import_module().

Instead, use the standard importlib module to dynamically import a module by name. With getattr you can then instantiate a class by its name:

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

You could also write:

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

This code is valid in python ≥ 2.7 (including python 3).


回答 2

用于getattr从字符串中的名称获取属性。换句话说,将实例获取为

instance = getattr(modul, class_name)()

Use getattr to get an attribute from a name in a string. In other words, get the instance as

instance = getattr(modul, class_name)()

回答 3

复制粘贴代码段:

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

Copy-paste snippet:

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

回答 4

如果要from foo.bar import foo2动态加载此句子,则应执行此操作

foo = __import__("foo")
bar = getattr(foo,"bar")
foo2 = getattr(bar,"foo2")

instance = foo2()

If you want this sentence from foo.bar import foo2 to be loaded dynamically, you should do this

foo = __import__("foo")
bar = getattr(foo,"bar")
foo2 = getattr(bar,"foo2")

instance = foo2()

回答 5

一个人可以简单地使用该pydoc.locate功能。

from pydoc import locate
my_class = locate("module.submodule.myclass")
instance = my_class()

One can simply use the pydoc.locate function.

from pydoc import locate
my_class = locate("module.submodule.myclass")
instance = my_class()

回答 6

在上面的示例中,我无法完全达到用例的目的,但是艾哈迈德让我最接近了(谢谢)。对于以后阅读此书的人来说,以下是对我有用的代码。

def get_class(fully_qualified_path, module_name, class_name, *instantiation):
    """
    Returns an instantiated class for the given string descriptors
    :param fully_qualified_path: The path to the module eg("Utilities.Printer")
    :param module_name: The module name eg("Printer")
    :param class_name: The class name eg("ScreenPrinter")
    :param instantiation: Any fields required to instantiate the class
    :return: An instance of the class
    """
    p = __import__(fully_qualified_path)
    m = getattr(p, module_name)
    c = getattr(m, class_name)
    instance = c(*instantiation)
    return instance

I couldn’t quite get there in my use case from the examples above, but Ahmad got me the closest (thank you). For those reading this in the future, here is the code that worked for me.

def get_class(fully_qualified_path, module_name, class_name, *instantiation):
    """
    Returns an instantiated class for the given string descriptors
    :param fully_qualified_path: The path to the module eg("Utilities.Printer")
    :param module_name: The module name eg("Printer")
    :param class_name: The class name eg("ScreenPrinter")
    :param instantiation: Any fields required to instantiate the class
    :return: An instance of the class
    """
    p = __import__(fully_qualified_path)
    m = getattr(p, module_name)
    c = getattr(m, class_name)
    instance = c(*instantiation)
    return instance