web-dev-qa-db-ja.com

pythonと同等のJava Class.forName()?

文字列引数を取り、Pythonでその文字列で指定されたクラスのオブジェクトを作成する必要があります。 Javaでは、Class.forName().newInstance()を使用します。 Pythonに同等のものはありますか?


回答ありがとうございます。私がやっていることを知りたい人に答えるには、コマンドライン引数をクラス名として使用し、インスタンス化します。私は実際にJythonでプログラミングを行っており、Javaクラス、したがってJavaの質の問題。getattr()がうまく機能しています。ありがとうございました。

87
Jason

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_モジュールにある場合、mfooモジュールになります
_getattr( m, 'baz' )を使用して、_foo.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)    
_

ループの最後で、mはクラスへの参照になります。これは、mが実際にはクラスそのものであることを意味します。たとえば、次のことができます。

_a = m() #instantiate a new instance of the class    
b = m( arg1, arg2 ) # pass arguments to the constructor
_
155
hasen

クラスがスコープ内にあると仮定します:

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)
25
Cody Brocious
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: 
11
Pat

さらに別の実装。

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)
4
grayhemp

あなたは最初からではなく真ん中からこれに近づいているようです。あなたは本当に何をしようとしているのですか?特定の文字列に関連付けられたクラスを見つけることは、目的を達成するための手段です。

あなた自身の精神的なリファクタリングを必要とするかもしれない問題を明確にすると、より良い解決策が現れるかもしれません。

たとえば、タイプ名と一連のパラメーターに基づいて保存済みオブジェクトをロードしようとしていますか? 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
3
Roger Pate

これは、python標準ライブラリ、unittest.TestLoader.loadTestsFromNameにあります。残念ながら、メソッドは追加のテスト関連アクティビティを実行しますが、この最初の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
1
bukzor