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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4821104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 17:40:21  来源:igfitidea点击:

Dynamic instantiation from string name of a class in dynamically imported module?

python

提问by Javier Novoa C.

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:

在 python 中,我必须实例化某个类,在字符串中知道它的名称,但是这个类“存在”在动态导入的模块中。一个例子如下:

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

我使用这种安排来使任何动态加载的模块由加载器类按照 dyn-loaded-modules 中的某些预定义行为使用...

采纳答案by Sven Marnach

You can use getattr

您可以使用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_()

回答by AFoglia

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

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

instance = getattr(modul, class_name)()

回答by Andrejs Cainikovs

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

回答by Ahmad Muzakki

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

如果你想from foo.bar import foo2动态加载这句话,你应该这样做

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

instance = foo2()

回答by SteveJ

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

回答by Régis B.

tl;dr

tl;博士

Import the root module with importlib.import_moduleand load the class by its name using getattrfunction:

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

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:

您可能不想使用__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'

Hereis what the python doc says about __import__:

是python doc所说的内容__import__

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

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

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

相反,使用标准importlib模块按名称动态导入模块。有了getattr那么你可以通过它的名字实例化一个类:

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

此代码在 python ≥ 2.7(包括 python 3)中有效。

回答by Xema

One can simply use the pydoc.locatefunction.

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

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