web-dev-qa-db-ja.com

Pythonクラスを動的にロードする方法

Pythonクラスの文字列を指定します。 my_package.my_module.MyClass、それをロードする最良の方法は何ですか?

言い換えれば、Javaの同等のClass.forName()、Pythonの関数を探しています。 Google App Engineで動作する必要があります。

これは、クラスのFQNを文字列として受け取り、クラスへの参照を返す関数であることが望ましいでしょう:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()
140
pjesi

pythonドキュメントから、必要な関数は次のとおりです。

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

単純な__import__が機能しない理由は、パッケージ文字列の最初のドットを超えるもののインポートは、インポートするモジュールの属性であるためです。したがって、次のようなものは機能しません。

__import__('foo.bar.baz.qux')

上記の関数を次のように呼び出す必要があります。

my_import('foo.bar.baz.qux')

または、あなたの例の場合:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

EDIT:私はこれについて少しオフでした。基本的にあなたがしたいことはこれです:

from my_package.my_module import my_class

上記の関数は、emptyfromlistがある場合にのみ必要です。したがって、適切な呼び出しは次のようになります。

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')
173
Jason Baker

独自にロールバックしたくない場合は、pydocモジュールで使用可能な関数があります。

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

ここにリストされている他のアプローチに対するこのアプローチの利点は、locateがモジュール内のオブジェクトだけでなく、指定されたドット付きパスでany pythonオブジェクトを見つけることです。例えばmy_package.my_module.MyClass.attr

あなたが彼らのレシピが何であるか興味があるなら、ここに関数があります:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

pydoc.safeimport関数に依存しています。そのためのドキュメントは次のとおりです。

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""
106
chadrik
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
76
Adam Spence
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)
29
Stan

Djangoを使用している場合、これを使用できます。 はい、OPはDjangoを要求しませんでしたが、Django_ソリューションを探してこの質問に出くわし、解決策を見つけられず、次の少年/ギャルのためにここに置きました。それを探します。

# It's available for v1.7+
# https://github.com/Django/django/blob/stable/1.7.x/Django/utils/module_loading.py
from Django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

reargparseのような.を持たないものをインポートする場合は、以下を使用してください。

re = __import__('re')
7
Javier Buzzi

OK、私にとってそれはそれが働いた方法です(私はPython 2.7を使用しています):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

次に、bはクラス「MyClass」のインスタンスです

1
lfvv

この問題を解決するために、__import__importlibで見つけたものを共有します。

Python 3.7.3を使用しています。

モジュールa.b.cのクラスdに到達しようとすると、

mod = __import__('a.b.c')

mod変数は、最上位の名前空間aを参照します。

クラスdを取得するには、

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

しようとしたら

mod = __import__('a.b.c')
d = getattr(mod, 'd')

実際にa.dを探しています。

importlibを使用しているとき、ライブラリがgetattrを再帰的に実行したと思います。したがって、importlib.import_moduleを使用すると、実際に最も深いモジュールのハンドルを取得します。

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d
1
Richard Wong

目的のクラスのインスタンスが既にある場合は、「type」関数を使用してそのクラス型を抽出し、これを使用して新しいインスタンスを構築できます。

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()
0
Jason DeMorrow