Namen der aktuellen Klasse abrufen?

102

Wie erhalte ich den Namen der Klasse, in der ich mich gerade befinde?

Beispiel:

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

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

Aufgrund der Art des Programms, mit dem ich verbunden bin (vistrails), kann ich es nicht __init__()zum Initialisieren verwenden input.

Jonathan Ginsburg
quelle

Antworten:

158

obj.__class__.__name__ Sie erhalten einen beliebigen Objektnamen, damit Sie Folgendes tun können:

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

Verwendung:

>>> c = Clazz()
>>> c.getName()
'Clazz'
Yuval Adam
quelle
1
Warum ist das nicht die akzeptierte Antwort? EDIT: Ok, der Umfang von OP ist nicht innerlich, sondern auf Klassenebene.
KomodoDave
6
@KomodoDave, weil dies auch im Methodenbereich falsch ist. Wenn Sie getNamevon einer untergeordneten Klasse aus aufrufen , wird der Name der untergeordneten Klasse ausgegeben. Es wird dann schwierig, wenn Sie WIRKLICH die Klasse wollen, mit der Sie arbeiten.
Kenet Jervet
@KenetJervet Sie meinen, wenn Sie getNamevon einer übergeordneten Klasse aufrufen , wird der Name der untergeordneten Klasse ausgegeben? Ok, um darauf hinzuweisen.
KomodoDave
5
In OO-Begriffen ist die Lösung (Rückgabe des tatsächlichen Namens der untergeordneten Laufzeitklasse, selbst wenn die getName()Methode zufällig in einer Oberklasse definiert ist) jedoch korrekt.
sxc731
22

Innerhalb des Hauptteils einer Klasse ist der Klassenname noch nicht definiert und daher nicht verfügbar. Können Sie nicht einfach den Namen der Klasse eingeben? Vielleicht müssen Sie mehr über das Problem sagen, damit wir eine Lösung für Sie finden können.

Ich würde eine Metaklasse erstellen, um diese Arbeit für Sie zu erledigen. Es wird zur Zeit der Klassenerstellung aufgerufen (konzeptionell ganz am Ende der Klasse: block) und kann die zu erstellende Klasse manipulieren. Ich habe das nicht getestet:

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'
Ned Batchelder
quelle
Um zu verdeutlichen, was ich versuche: Ich muss eine Klassenvariable, 'input', außerhalb einer Methode erstellen und initialisieren . Ich habe eine Reihe kleiner Klassen, die jeweils 'get_input' mit ihrem Klassennamen als Parameter aufrufen müssen. Ich versuche dies zu verallgemeinern, damit ich nicht zu jeder Klasse gehen muss (es werden ungefähr 100 sein) und den Namen der Klasse eingeben muss.
Jonathan Ginsburg
OK, ich habe meine Antwort mit einer Metaklasse aktualisiert, die helfen sollte.
Ned Batchelder
1
Worauf bezieht sich MyTypedie superZeile in InputAssigningMetaclass?
A.Wan
16

Sie können über die privaten Attribute der Klasse darauf zugreifen:

cls_name = self.__class__.__name__

BEARBEITEN:

Wie gesagt Ned Batcheler, würde dies im Klassenkörper nicht funktionieren, aber es würde in einer Methode funktionieren.

mdeous
quelle
11

PEP 3155 eingeführt __qualname__, das in Python 3.3 implementiert wurde.

Bei Funktionen und Klassen der obersten Ebene entspricht das __qualname__Attribut dem __name__Attribut. Für verschachtelte Klassen, Methoden und verschachtelte Funktionen __qualname__enthält das Attribut einen gepunkteten Pfad, der von der obersten Ebene des Moduls zum Objekt führt.

Es ist innerhalb der Definition einer Klasse oder einer Funktion zugänglich, zum Beispiel:

class Foo:
    print(__qualname__)

wird effektiv gedruckt Foo. Sie erhalten den vollständig qualifizierten Namen (mit Ausnahme des Modulnamens), daher möchten Sie ihn möglicherweise auf den .Charakter aufteilen .

Es gibt jedoch keine Möglichkeit, einen tatsächlichen Überblick über die zu definierende Klasse zu erhalten.

>>> class Foo:
...     print('Foo' in globals())
... 
False
Rechtes Bein
quelle
7

EDIT: Ja, du kannst; aber du musst schummeln: Der aktuell ausgeführte Klassenname ist auf dem Aufrufstapel vorhanden, und das tracebackModul ermöglicht dir den Zugriff auf den Stapel.

>>> 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'

Ich würde dies jedoch nicht tun. Meine ursprüngliche Antwort ist immer noch meine eigene Präferenz als Lösung. Ursprüngliche Antwort:

Die wahrscheinlich einfachste Lösung ist die Verwendung eines Dekorateurs, der Neds Antwort mit Metaklassen ähnelt, jedoch weniger mächtig ist (Dekorateure sind zu schwarzer Magie fähig, Metaklassen jedoch zu alter, okkulter schwarzer Magie).

>>> 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'
>>> 
SingleNegationElimination
quelle
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()
Pavel Patrin
quelle
1

Ich denke, es sollte so sein:

    class foo():
        input = get_input(__qualname__)
Shtefan
quelle