Obtenir le nom de la classe actuelle?

102

Comment obtenir le nom de la classe dans laquelle je suis actuellement?

Exemple:

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

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

En raison de la nature du programme avec lequel je m'interface (vistrails), je ne peux pas utiliser __init__()pour initialiser input.

Jonathan Ginsburg
la source

Réponses:

158

obj.__class__.__name__ vous obtiendrez n'importe quel nom d'objet, vous pouvez donc le faire:

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

Usage:

>>> c = Clazz()
>>> c.getName()
'Clazz'
Yuval Adam
la source
1
Pourquoi n'est-ce pas la réponse acceptée? EDIT: La portée d'Ok OP n'est pas intérieure, c'est au niveau de la classe.
KomodoDave
6
@KomodoDave, car c'est faux, même dans la portée de la méthode. Lorsque vous appelez à getNamepartir d'une classe enfant, il affichera le nom de la classe enfant. Cela devient alors délicat si vous voulez VRAIMENT la classe avec laquelle vous travaillez.
Kenet Jervet
@KenetJervet Vous voulez dire que lorsque vous appelez getNamedepuis une classe parent, le nom de la classe enfant sera affiché ? Ok ty pour le signaler.
KomodoDave
5
En termes OO, la solution (renvoyer le nom de la classe enfant à l'exécution même si la getName()méthode est définie dans une superclasse) est correcte.
sxc731
22

Dans le corps d'une classe, le nom de la classe n'est pas encore défini, il n'est donc pas disponible. Ne pouvez-vous pas simplement taper le nom de la classe? Peut-être avez-vous besoin d'en dire plus sur le problème afin que nous puissions trouver une solution pour vous.

Je créerais une métaclasse pour faire ce travail pour vous. Il est appelé au moment de la création de la classe (conceptuellement à la toute fin de la classe: block), et peut manipuler la classe en cours de création. Je n'ai pas testé ceci:

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
la source
POUR clarifier ce que j'essaie de faire: j'ai besoin de créer et d'initialiser une variable de classe, «entrée», en dehors d'une méthode . J'ai un tas de petites classes, chacune qui doit appeler «get_input» en utilisant leur nom de classe comme paramètre. J'essaie de généraliser cela pour ne pas avoir à aller dans chaque classe (il y en aura une centaine) et à taper le nom de la classe.
Jonathan Ginsburg
OK, j'ai mis à jour ma réponse avec une métaclasse qui devrait aider.
Ned Batchelder
1
À quoi fait référence MyTypedans la superligne InputAssigningMetaclass?
A.Wan
16

Vous pouvez y accéder par les attributs privés de la classe:

cls_name = self.__class__.__name__

ÉDITER:

Comme indiqué par Ned Batcheler, cela ne fonctionnerait pas dans le corps de la classe, mais dans une méthode.

mdeous
la source
11

PEP 3155 introduit __qualname__, qui a été implémenté dans Python 3.3.

Pour les fonctions et classes de niveau supérieur, l' __qualname__attribut est égal à l' __name__attribut. Pour les classes, méthodes et fonctions imbriquées, l' __qualname__attribut contient un chemin en pointillé menant à l'objet à partir du niveau supérieur du module.

Il est accessible depuis la définition même d'une classe ou d'une fonction, donc par exemple:

class Foo:
    print(__qualname__)

imprimera efficacement Foo. Vous obtiendrez le nom complet (à l'exclusion du nom du module), vous voudrez peut-être le diviser sur le .personnage.

Cependant, il n'existe aucun moyen d'obtenir un handle réel sur la classe en cours de définition.

>>> class Foo:
...     print('Foo' in globals())
... 
False
Jambe droite
la source
7

EDIT: Oui, vous pouvez; mais vous devez tricher: le nom de la classe en cours d'exécution est présent sur la pile d'appels, et le tracebackmodule vous permet d'accéder à la pile.

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

Cependant, je ne ferais pas cela; Ma réponse initiale est toujours ma propre préférence comme solution. Réponse originale:

probablement la solution la plus simple est d'utiliser un décorateur, qui est similaire à la réponse de Ned impliquant des métaclasses, mais moins puissant (les décorateurs sont capables de magie noire, mais les métaclasses sont capables de magie noire ancienne et occulte )

>>> 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
la source
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
la source
1

Je pense que ça devrait être comme ça:

    class foo():
        input = get_input(__qualname__)
Shtefan
la source