101

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


回答ありがとうございます。私が何をしているのか知りたい人に答えるために: コマンドライン引数をクラス名として使用し、それをインスタンス化したいと思います。私は実際にJythonでプログラミングし、Javaクラスをインスタンス化しているため、質問のJava性があります。 getattr()よく働く。どうもありがとう。

4

7 に答える 7

178

Python でのリフレクションは、Java でのリフレクションよりもはるかに簡単で、はるかに柔軟です。

このチュートリアルを読むことをお勧めします

完全修飾クラス名を取り、クラスを返す直接関数 (私が知っている) はありませんが、それを構築するために必要なすべての要素があり、それらを接続することができます。

ただし、ちょっとしたアドバイス: Python を使用している場合は、Java スタイルでプログラミングしようとしないでください。

あなたが何をしようとしているのかを説明できれば、より Pythonic な方法を見つけるお手伝いができるかもしれません。

これがあなたが望むことをする関数です:

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モジュール内にある場合m、モジュールは、使用foo
する参照を簡単に取得できますfoo.bazgetattr( 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)    

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

a = m() #instantiate a new instance of the class    
b = m( arg1, arg2 ) # pass arguments to the constructor
于 2009-01-17T08:25:39.370 に答える
27

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

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)
于 2009-01-17T08:13:05.857 に答える
20
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: 
于 2015-05-05T01:00:38.220 に答える
4

さらに別の実装。

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)
于 2010-08-31T14:41:58.940 に答える
3

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

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

例: タイプ名とパラメータのセットに基づいて、保存されたオブジェクトをロードしようとしていますか? Python はこれを unpickle と綴っています。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
于 2009-01-17T15:37:40.733 に答える
2

これは、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
于 2013-12-10T23:54:55.637 に答える