web-dev-qa-db-fra.com

Obtenir le nom de la classe en cours?

Comment puis-je 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.

78
Jonathan Ginsburg

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

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

Usage:

>>> c = Clazz()
>>> c.getName()
'Clazz'
121
Yuval Adam

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 devrez-vous en dire plus sur le problème pour que nous puissions trouver une solution à votre problème.

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'
19
Ned Batchelder

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

cls_name = self.__class__.__name__

MODIFIER:

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

14
mdeous

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 module traceback 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 le ferais pas; Ma réponse initiale reste ma propre préférence en tant que solution. Réponse originale:

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

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

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

Pour les fonctions et les classes de niveau supérieur, l'attribut __qualname__ est égal à l'attribut __name__. Pour les classes, méthodes et fonctions imbriquées imbriquées, l'attribut __qualname__ 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, par exemple:

class Foo:
    print(__qualname__)

va effectivement imprimer Foo. Vous obtiendrez le nom complet (à l’exclusion du nom du module), de sorte que vous voudrez peut-être le scinder en ..

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

>>> class Foo:
...     print('Foo' in globals())
... 
False
2
Right leg
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
Pavel Patrin

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

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