現在のクラスの名前を取得しますか?


102

現在参加しているクラスの名前を取得するにはどうすればよいですか?

例:

def get_input(class_name):
    [do things]
    return class_name_result

class foo():
    input = get_input([class name goes here])

(vistrails)とやり取りするプログラムの性質上、の__init__()初期化には使用できませんinput

回答:


158

obj.__class__.__name__ オブジェクト名を取得するので、これを行うことができます:

class Clazz():
    def getName(self):
        return self.__class__.__name__

使用法:

>>> c = Clazz()
>>> c.getName()
'Clazz'

1
なぜこれは受け入れられた答えではないのですか?編集:Ok OPのスコープは内部ではなく、クラスレベルです。
KomodoDave 2014年

6
@KomodoDave、これはメソッドのスコープ内でも誤りです。getName子クラスから呼び出すと、子クラス名が出力されます。作業中のクラスが本当に必要な場合は、注意が必要です。
Kenet Jervet 2015年

@KenetJervet クラスgetNameから呼び出すと、子クラス名が出力されるという意味ですか?指摘してくれてありがとう。
KomodoDave

5
OO用語では、解決策(getName()メソッドがたまたまスーパークラスで定義されている場合でも実際のランタイムの子クラス名を返す)は正しいです。
sxc731

22

クラスの本体内では、クラス名がまだ定義されていないため、使用できません。クラスの名前を単純に入力できませんか?多分私達はあなたのための解決策を見つけることができるように問題についてもっと話す必要があります。

この作業を行うメタクラスを作成します。これは、クラスの作成時に呼び出され(概念的には、クラス:ブロックの最後)、作成されるクラスを操作できます。私はこれをテストしていません:

class InputAssigningMetaclass(type):
    def __new__(cls, name, bases, attrs):
        cls.input = get_input(name)
        return super(MyType, cls).__new__(cls, name, bases, newattrs)

class MyBaseFoo(object):
    __metaclass__ = InputAssigningMetaclass

class foo(MyBaseFoo):
    # etc, no need to create 'input'

class foo2(MyBaseFoo):
    # etc, no need to create 'input'

私が何をしようとしているのかを明確にするために:メソッドの外でクラス変数「input」を作成して初期化する必要があります。私はたくさんの小さなクラスを持っています。それぞれがクラス名をパラメーターとして使用して 'get_input'を呼び出す必要があります。私はこれを一般化しようとしているので、各クラス(100程度になるでしょう)に行ってクラスの名前を入力する必要はありません。
ジョナサンギンズバーグ2011

OK、私は役立つはずのメタクラスで私の答えを更新しました。
Ned Batchelder、2011

1
MyTypesuper行で何をInputAssigningMetaclass参照していますか?
A.Wan

16

クラスのプライベート属性でアクセスできます:

cls_name = self.__class__.__name__

編集:

で述べたようにNed Batcheler、これはクラス本体では機能しませんが、メソッドでは機能します。


11

PEP 3155が導入__qualname__され、Python 3.3で実装されました。

トップレベルの関数とクラスの場合、__qualname__属性は属性と同じ__name__です。ネストされたクラス、メソッド、およびネストされた関数の場合、__qualname__属性には、モジュールのトップレベルからオブジェクトに至る点線のパスが含まれます。

これは、クラスまたは関数の定義そのものからアクセスできるため、たとえば次のようになります。

class Foo:
    print(__qualname__)

効果的に印刷されますFoo。完全修飾名(モジュールの名前を除く)を取得するため、.文字で分割することができます。

ただし、定義されているクラスの実際のハンドルを取得する方法はありません。

>>> class Foo:
...     print('Foo' in globals())
... 
False

7

編集:はい、できます。しかし、あなたはチートする必要があります:現在実行中のクラス名はコールスタックに存在し、tracebackモジュールはスタックにアクセスすることを許可します。

>>> import traceback
>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> class foo(object):
...      _name = traceback.extract_stack()[-1][2]
...     input = get_input(_name)
... 
>>> 
>>> foo.input
'sbb'

しかし、私はこれをしません。私の最初の答えは、依然として解決策としての私の好みです。元の答え:

おそらく最も簡単な解決策は、メタクラスに関するNedの回答に似ていますが、それほど強力ではないデコレータを使用することです(デコレータはブラックマジックに対応していますが、メタクラスは古代のオカルトブラックマジックに対応しています)。

>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> def inputize(cls):
...     cls.input = get_input(cls.__name__)
...     return cls
... 
>>> @inputize
... class foo(object):
...     pass
... 
>>> foo.input
'sbb'
>>> 

1
import sys

def class_meta(frame):
    class_context = '__module__' in frame.f_locals
    assert class_context, 'Frame is not a class context'

    module_name = frame.f_locals['__module__']
    class_name = frame.f_code.co_name
    return module_name, class_name

def print_class_path():
    print('%s.%s' % class_meta(sys._getframe(1)))

class MyClass(object):
    print_class_path()

1

私は、それはこのようになるはずだと思います:

    class foo():
        input = get_input(__qualname__)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.