19

だから私はこの問題を抱えています、私はこの方法でPythonクラスの名前を取得したい:

class TestClass():
    myName = (get class name here automatically)
    saveDirectory = os.path.join(saveDir, myName) # so i can save it in unique location
    def __init__(self):
        pass # do something

ただし、が作成され__class__.__name__た時点では、実際にはまだ存在していないようmyNameです。__init__()だから私は次のようにそれを関数に入れることを余儀なくされました:

class TestClass():
    def __init__(self):
        self.myName = self.__class__.__name__
        saveDirectory = os.path.join(saveDir, self.myName) # so i can save it in unique location
        pass # do something

しかし、これには大きな問題があります。クラスをインスタンス化するまでクラスの名前を取得できないためです。クラスのインスタンスごとに数ギガバイトのデータを作成して、saveDirectory に保存するつもりです。後で使用されます。したがって、現在のソリューションを実際に進めたくありません。

私が意図したとおりにクラス名を取得する方法はありますか? それとも私は夢を見ているだけですか?

編集:

素晴らしい提案をありがとう。メタクラスについて少し時間をかけて見ていきます。それ以外の場合は、おそらくグローバルに辞書を作成し、代わりにこれらのインスタンス化されたクラスへの参照を持ちます。

4

7 に答える 7

8

メソッドを使用するだけですか?

class TestClass(object):
    @classmethod
    def get_save_directory(cls):
        return os.path.join(save_dir, cls.__name__)

または、保存ディレクトリを示すクラス属性を持つこともできます。少ない魔法は通常良いことです。さらに、ストレージを壊すことなく、後でクラスの名前を変更できます。

また、何?ギガバイト?!

于 2013-01-24T23:59:41.697 に答える
7

クラス定義中に実際にしようとしていることを実行する唯一の方法は、メタクラスを使用することです。

def saveDirMeta(name, bases, dct):
    dct['saveDirectory'] = os.path.join(saveDir, name)
    return type(name, bases, dct)

class TestClass(object):
    __metaclass__ = saveDirMeta  # this adds the 'saveDirectory' attribute
    def __init__(self):
        pass # do something

または Python 3.x の場合:

class TestClass(metaclass=saveDirMeta):
    def __init__(self):
        pass # do something

これは、以下を使用するよりも明確ではありません。

class TestClass():
    saveDirectory = os.path.join(saveDir, 'TestClass')
    def __init__(self):
        pass # do something
于 2013-01-25T00:10:08.990 に答える
2

F J's answerのメタクラス以外に、他に2 つの方法が考えられます。見栄えの良いものから始めます。メタクラスを使用する必要はありません。記述子が完全に適切な場合もあります。

class ClassNameDescriptor(object):
    def __get__(self, instance, owner):
        return owner.__name__

class BaseClass(object):
    name = ClassNameDescriptor()

class Foo(BaseClass):
    pass

逆に、クラス本体の内部からクラス名が本当に必要な場合は(ほとんどありませんが)、コール スタックをスヌープできます。ソースに表示されるクラス名は、クラス定義によって実行されるコード オブジェクトにあります。

import sys

def get_class_name_from_inside_class():
    return sys._getframe().f_back.f_code.co_name

class Foo(object):
    name = get_class_name_from_inside_class()
    print name

これまでに提示されたもののうち、この最後のものだけが、名前を文字列としてクラス本体内から使用できます。残念ながら、これは Python のすべてのバージョンで機能するわけではありません。特に、IronPython はコール スタック イントロスペクションを実装していません。 DLR では使用できないためです。

スタックをイントロスペクトせずに、ポータブルに取得する方法があります。メタクラスを使用して FJ が提供する回答に似ていますが、代わり__prepare__に Python 3 で利用可能な機能を使用します。

class namedMeta(type):
    def __prepare__(mcls, name, bases, **kwargs):
        return {'name': name}

class Foo(metaclass=named):
    print name
于 2013-10-06T02:28:30.060 に答える
2

クラスが存在しないため、あなたがしていることは不可能だと思います:

myName = (get class name here automatically)

しかし、クラスが解釈された直後に、クラス オブジェクトを他の関数に渡して、その仕事を行うことができます。

In [1]: def save_class(cl):
    myName = cl.__name__
    print myName        #or do whatever you wanna do here
   ...:     

In [2]: class A:pass

In [3]: save_class(A)
A
于 2013-01-25T00:06:22.817 に答える
2

授業の通訳中、そこにはまだ「あそこ」がありません。そうです、あなたの最初の例が示していることは不可能です。しかし、クラスが技術的に存在する前に、これを知る必要がある理由を説明してください。

その未解決の質問に対する良い答えがなければ、クラスの名前を次から取得しようとすることになります。

1. outside the interpreted class definition, uninstantiated

    class demo(object):
        pass

    print demo.__name__ # 'demo'


2. from within the class definition, uninstantiated (or instantiated ;-)

    class demo2(object):
        @classmethod
        def myName(cls):
            return cls.__name__

    print demo2.myName() # 'demo2'
    print demo2().myName() # 'demo2'


or

3. within an actual instance of the class

    class demo3(object):
        def myClassName(self):
            return self.__class__.__name__

    print demo3().myClassName() # 'demo3'

それを超えて、質問を編集し、インスタンス化の前にクラス定義の内部で最初の試行が希望どおりに機能する必要がある理由を説明する詳細を追加してください.2番目の例には問題があります. また、saveDir はどのように渡されますか? (クラス外のグローバル?) 作業したいものをどのように使用するつもりかを示すコードを示してください。文字通りではないにしても、実際には、ここからそこにたどり着くように再設計する方法があるかもしれません。

于 2013-10-06T00:16:14.037 に答える