¿Obtener el nombre de la clase actual?

102

¿Cómo obtengo el nombre de la clase en la que estoy actualmente?

Ejemplo:

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

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

Debido a la naturaleza del programa con el que estoy interactuando (vistrails), no puedo usar __init__()para inicializar input.

Jonathan Ginsburg
fuente

Respuestas:

158

obj.__class__.__name__ obtendrá cualquier nombre de objeto, por lo que puede hacer esto:

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

Uso:

>>> c = Clazz()
>>> c.getName()
'Clazz'
Yuval Adam
fuente
1
¿Por qué no es esta la respuesta aceptada? EDITAR: Ok, el alcance de OP no es interno, está a nivel de clase.
KomodoDave
6
@KomodoDave, porque esto es incorrecto, incluso en el alcance del método. Cuando llama getNamedesde una clase secundaria, se generará el nombre de la clase secundaria. Entonces se vuelve complicado si REALMENTE desea la clase con la que está trabajando.
Kenet Jervet
@KenetJervet ¿Quieres decir que cuando llamas getNamedesde una clase principal , se mostrará el nombre de la clase secundaria? Está bien por señalar eso.
KomodoDave
5
Sin embargo, en términos OO, la solución (que devuelve el nombre de la clase secundaria en tiempo de ejecución real incluso si el getName()método está definido en una superclase) es correcta.
sxc731
22

Dentro del cuerpo de una clase, el nombre de la clase aún no está definido, por lo que no está disponible. ¿No puedes simplemente escribir el nombre de la clase? Tal vez necesite decir más sobre el problema para que podamos encontrar una solución para usted.

Crearía una metaclase para hacer este trabajo por ti. Se invoca en el momento de la creación de la clase (conceptualmente al final de la clase: bloque) y puede manipular la clase que se está creando. No he probado esto:

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
fuente
PARA aclarar lo que estoy tratando de hacer: necesito crear e inicializar una variable de clase, 'entrada', fuera de un método . Tengo un montón de clases pequeñas, cada una de las cuales debe llamar a 'get_input' usando su nombre de clase como parámetro. Estoy tratando de generalizar esto para no tener que ir a cada clase (habrá 100 más o menos) y escribir el nombre de la clase.
Jonathan Ginsburg
OK, he actualizado mi respuesta con una metaclase que debería ayudar.
Ned Batchelder
1
¿A qué se refiere MyTypela superlínea en InputAssigningMetaclass?
A.Wan
16

Puede acceder a él mediante los atributos privados de la clase:

cls_name = self.__class__.__name__

EDITAR:

Como dijo Ned Batcheler, esto no funcionaría en el cuerpo de la clase, pero sí en un método.

mdeous
fuente
11

Se introdujo PEP 3155__qualname__ , que se implementó en Python 3.3.

Para funciones y clases de nivel superior, el __qualname__atributo es igual al __name__atributo. Para clases anidadas, métodos y funciones anidadas, el __qualname__atributo contiene una ruta de puntos que conduce al objeto desde el nivel superior del módulo.

Es accesible desde la propia definición de una clase o función, por ejemplo:

class Foo:
    print(__qualname__)

imprimirá efectivamente Foo. Obtendrá el nombre completo (excluyendo el nombre del módulo), por lo que es posible que desee dividirlo en el .personaje.

Sin embargo, no hay forma de obtener un control real de la clase que se está definiendo.

>>> class Foo:
...     print('Foo' in globals())
... 
False
Pierna derecha
fuente
7

EDITAR: Sí, puedes; pero tienes que hacer trampa: el nombre de la clase que se está ejecutando actualmente está presente en la pila de llamadas y el tracebackmódulo te permite acceder a la pila.

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

Sin embargo, yo no haría esto; Mi respuesta original sigue siendo mi propia preferencia como solución. Respuesta original:

probablemente la solución más simple es usar un decorador, que es similar a la respuesta de Ned que involucra metaclases, pero menos poderosa (los decoradores son capaces de magia negra, pero las metaclases son capaces de magia negra antigua y oculta )

>>> 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
fuente
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
fuente
1

Creo que debería ser así:

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