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()
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')
独自にロールバックしたくない場合は、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)."""
import importlib
module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
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)
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')
re
やargparse
のような.
を持たないものをインポートする場合は、以下を使用してください。
re = __import__('re')
OK、私にとってそれはそれが働いた方法です(私はPython 2.7を使用しています):
a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()
次に、bはクラス「MyClass」のインスタンスです
この問題を解決するために、__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
目的のクラスのインスタンスが既にある場合は、「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()