Динамическая инстанция Python из имени строки класса в динамически импортированном модуле
В 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
некоторый динамически загруженный модуль script:
class myName:
# etc...
Я использую эту компоновку, чтобы сделать любой динамически загруженный модуль, который будет использоваться классом-загрузчиком, после определенных предопределенных действий в динамически нагруженных модулях...
Любые идеи приветствуются.
Ответы
Ответ 1
Вы можете использовать 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_()
Ответ 2
ТЛ; др
Импортируйте корневой модуль с помощью 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'
Вот что говорит __import__
о __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).
Ответ 3
Используйте getattr
, чтобы получить атрибут от имени в строке. Другими словами, получите экземпляр как
instance = getattr(modul, class_name)()
Ответ 4
Скопировать-вставить фрагмент:
import importlib
def str_to_class(module_name, class_name)
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
Ответ 5
Если вы хотите, чтобы это предложение from foo.bar import foo2
загружалось динамически, вы должны сделать это
foo = __import__("foo")
bar = getattr(foo,"bar")
foo2 = getattr(bar,"foo2")
instance = foo2()
Ответ 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
Ответ 7
Можно просто использовать функцию pydoc.locate
.
from pydoc import locate
my_class = locate("module.submodule.myclass")
instance = my_class()