動的にインポートされたモジュールのクラスの文字列名からの動的インスタンス化?


179

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

some-dynamically-loaded-moduleスクリプト:

class myName:
  # etc...

この配置を使用して、dyn-loaded-modulesの特定の事前定義された動作に従って、ローダークラスが動的にロードされるモジュールを使用できるようにします...

回答:


251

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

3
module = __import__(module, fromlist=[name])私のためだけに働いた。
umpirsky、2012年

16
上記のインポート方法Svenで問題が発生している場合は、importlib.import_moduleの代わりに次の方法を使用すると、コードがうまく機能することがわかりました。次のように使用できます:module = importlib.import_module(module_name)
jpennell

@jpennell回答として投稿する必要があります。–によって返される文字列を直接使用できるようにすると、多くの場合、より便利になりますobj.__module__
Anentropic

importlib.import_module必要に応じて.pyファイルをpycに読み込み、完全なmodule.name.pathing.to.get.to.theクラスを処理します。__import__django環境では、これらのいずれも実行しません(これ以外ではテストされていません)
James

122

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__

注:これは、importlib.import_module()とは異なり、日常のPythonプログラミングでは不要な高度な関数です。

代わりに、標準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を含む)で有効です。


1
多分私はあなたの答えを理解していませんが、インポートを使用してサブモジュールをインポートしました:__import __( "module。" + submodule_name_string)
Javier Novoa C.

AttributeErrorに次のコードの結果:mod = __import__("os.path"); mod.join以下のdoesnt中:mod = importlib.import_module("os.path"); mod.join
レジスB.

ああ、そうです、あなたの言うとおりですが、os.path.joinメソッドを取得するために次のことを行いました。getattr(sys.modules ["os.path"]、 "join")
Javier Novoa C.

ハ!そして、それを使用すると、「インポート」は不要なXD であることがわかります
Javier Novoa C.

2
回答としてマークされたオプションは私には(サブモジュールを使用して)機能しませんでしたが、この回答は機能しました。それはモジュールを動的にロードするためのより一般的なソリューションなので、それが答えになるはずだと思います。
rkachach

14

getattr文字列の名前から属性を取得するために使用します。つまり、次のようにインスタンスを取得します

instance = getattr(modul, class_name)()

10

スニペットをコピーして貼り付け:

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

5

この文from foo.bar import foo2を動的にロードしたい場合は、これを行う必要があります

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

instance = foo2()

4

単純にpydoc.locate関数を使用できます。

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

2

上記の例では、ユースケースに到達することはできませんでしたが、Ahmadが最も近くなりました(ありがとう)。将来これを読む人のために、これは私のために働いたコードです。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.