PythonにはJava Class.forName()に相当するものがありますか?
-
19-08-2019 - |
質問
文字列引数を取り、Pythonでその文字列で指定されたクラスのオブジェクトを作成する必要があります。 Javaでは、Class.forName().newInstance()
を使用します。 Pythonに同等のものはありますか?
ご回答ありがとうございます。私が何をしているか知りたい人に答えるには、コマンドライン引数をクラス名として使用し、インスタンス化します。私は実際にJythonでプログラミングし、Javaクラスをインスタンス化しています。したがって、Javaの問題です。 getattr()
うまくいきます。どうもありがとう。
解決
Pythonでの反射は、Javaでの反射よりもはるかに簡単で、はるかに柔軟です。
こちらを読むことをお勧めしますチュートリアル
完全修飾クラス名を取得してクラスを返す直接関数(私が知っている)はありませんが、それを構築するために必要なすべての要素があり、それらを一緒に接続できます。
ちょっとしたアドバイス:pythonを使用しているときは、Javaスタイルでプログラミングしないでください。
あなたがやろうとしていることを説明できれば、もっとPython的な方法を見つけるのを手伝うことができます。
これはあなたが望むことをする関数です:
def get_class( kls ):
parts = kls.split('.')
module = ".".join(parts[:-1])
m = __import__( module )
for comp in parts[1:]:
m = getattr(m, comp)
return m
この関数の戻り値は、クラス自体であるかのように使用できます。
使用例は次のとおりです。
>>> D = get_class("datetime.datetime")
>>> D
<type 'datetime.datetime'>
>>> D.now()
datetime.datetime(2009, 1, 17, 2, 15, 58, 883000)
>>> a = D( 2010, 4, 22 )
>>> a
datetime.datetime(2010, 4, 22, 0, 0)
>>>
それはどのように機能しますか
__import__
を使用してクラスを保持するモジュールをインポートします。これには、最初に完全修飾名からモジュール名を抽出する必要がありました。次に、モジュールをインポートします:
m = __import__( module )
この場合、m
は最上位モジュールのみを参照します、
たとえば、クラスがfoo.baz
モジュールにある場合、foo
はモジュールgetattr( m, 'baz' )
になります
gettatr
foo.baz.bar.Model
への参照を簡単に取得できます。
トップレベルモジュールからクラスにアクセスするには、クラス名の一部で再帰的に<=>を使用する必要があります
たとえば、クラス名が<=>の場合、これを行います:
m = __import__( "foo.baz.bar" ) #m is package foo
m = getattr( m, "baz" ) #m is package baz
m = getattr( m, "bar" ) #m is module bar
m = getattr( m, "Model" ) #m is class Model
これは、このループで何が起こっているかです:
for comp in parts[1:]:
m = getattr(m, comp)
ループの終わりで、<=>はクラスへの参照になります。これは、<=>が実際にはクラスそのものであることを意味します。たとえば、次のようにできます。
a = m() #instantiate a new instance of the class
b = m( arg1, arg2 ) # pass arguments to the constructor
他のヒント
クラスがスコープ内にあると仮定します:
globals()['classname'](args, to, constructor)
それ以外の場合:
getattr(someModule, 'classname')(args, to, constructor)
編集:注、getattrに「foo.bar」のような名前を付けることはできません。で分割する必要があります。そして、各ピースを左から右にgetattr()を呼び出します。これはそれを処理します:
module, rest = 'foo.bar.baz'.split('.', 1)
fooBar = reduce(lambda a, b: getattr(a, b), rest.split('.'), globals()[module])
someVar = fooBar(args, to, constructor)
def import_class_from_string(path):
from importlib import import_module
module_path, _, class_name = path.rpartition('.')
mod = import_module(module_path)
klass = getattr(mod, class_name)
return klass
使用法
In [59]: raise import_class_from_string('google.appengine.runtime.apiproxy_errors.DeadlineExceededError')()
---------------------------------------------------------------------------
DeadlineExceededError Traceback (most recent call last)
<ipython-input-59-b4e59d809b2f> in <module>()
----> 1 raise import_class_from_string('google.appengine.runtime.apiproxy_errors.DeadlineExceededError')()
DeadlineExceededError:
さらに別の実装。
def import_class(class_string):
"""Returns class object specified by a string.
Args:
class_string: The string representing a class.
Raises:
ValueError if module part of the class is not specified.
"""
module_name, _, class_name = class_string.rpartition('.')
if module_name == '':
raise ValueError('Class name must contain module part.')
return getattr(
__import__(module_name, globals(), locals(), [class_name], -1),
class_name)
最初からではなく、真ん中からこれに近づいているようです。あなたは本当に何をしようとしているのですか?特定の文字列に関連付けられたクラスを見つけることは、目的を達成するための手段です。
あなた自身の精神的なリファクタリングを必要とするかもしれない問題を明確にすると、より良い解決策が現れるかもしれません。
たとえば、タイプ名とパラメーターのセットに基づいて、保存されたオブジェクトをロードしようとしていますか? Pythonはこのアンピクルをつづります。 pickleモジュールをご覧ください。そして、アンピクル処理はあなたが説明したとおりに行いますが、内部的にどのように動作するかを心配する必要はありません:
>>> class A(object):
... def __init__(self, v):
... self.v = v
... def __reduce__(self):
... return (self.__class__, (self.v,))
>>> a = A("example")
>>> import pickle
>>> b = pickle.loads(pickle.dumps(a))
>>> a.v, b.v
('example', 'example')
>>> a is b
False
これは、unittest.TestLoader.loadTestsFromNameとしてPython標準ライブラリにあります。残念ながら、このメソッドはさらにテスト関連のアクティビティを実行しますが、この最初のhaは再利用可能に見えます。テスト関連の機能を削除するために編集しました:
def get_object(name):
"""Retrieve a python object, given its dotted.name."""
parts = name.split('.')
parts_copy = parts[:]
while parts_copy:
try:
module = __import__('.'.join(parts_copy))
break
except ImportError:
del parts_copy[-1]
if not parts_copy: raise
parts = parts[1:]
obj = module
for part in parts:
parent, obj = obj, getattr(obj, part)
return obj