Obter o nome da turma atual?

102

Como faço para obter o nome da classe em que estou atualmente?

Exemplo:

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

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

Devido à natureza do programa com o qual estou interagindo (vistrails), não posso usar __init__()para inicializar input.

Jonathan Ginsburg
fonte

Respostas:

158

obj.__class__.__name__ obterá qualquer nome de objeto, para que você possa fazer o seguinte:

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

Uso:

>>> c = Clazz()
>>> c.getName()
'Clazz'
Yuval Adam
fonte
1
Por que essa não é a resposta aceita? EDIT: Ok, o escopo do OP não é interno, está no nível de classe.
KomodoDave
6
@KomodoDave, porque está errado, mesmo no escopo do método. Quando você chama getNamede uma classe filha, o nome da classe filha é gerado. Então fica complicado se você realmente quer a classe com a qual está trabalhando.
Kenet Jervet
@KenetJervet Você quer dizer que quando você chama a getNamepartir de uma classe pai, ele produzirá o nome da classe filha? Ok ty por apontar isso.
KomodoDave
5
Em termos OO, a solução (retornando o nome real da classe filha do tempo de execução mesmo se o getName()método for definido em uma superclasse) está correta.
sxc731
22

Dentro do corpo de uma classe, o nome da classe ainda não foi definido, portanto, não está disponível. Você não pode simplesmente digitar o nome da classe? Talvez você precise falar mais sobre o problema para que possamos encontrar uma solução para você.

Eu criaria uma metaclasse para fazer esse trabalho para você. É invocado no momento da criação da classe (conceitualmente no final da classe: bloco) e pode manipular a classe que está sendo criada. Eu não testei isso:

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
fonte
PARA esclarecer o que estou tentando fazer: eu preciso criar e inicializar uma variável de classe, 'input', fora de um método . Eu tenho um monte de pequenas classes, cada uma delas deve chamar 'get_input' usando seu nome de classe como parâmetro. Estou tentando generalizar isso para não ter que ir a cada classe (serão 100 ou mais) e digitar o nome da classe.
Jonathan Ginsburg
OK, atualizei minha resposta com uma metaclasse que deve ajudar.
Ned Batchelder
1
A que se refere MyTypea superlinha em InputAssigningMetaclass?
A.Wan 01 de
16

Você pode acessá-lo pelos atributos privados da classe:

cls_name = self.__class__.__name__

EDITAR:

Como disse Ned Batcheler, isso não funcionaria no corpo da classe, mas funcionaria em um método.

maravilhoso
fonte
11

PEP 3155 introduzido __qualname__, que foi implementado em Python 3.3.

Para funções e classes de nível superior, o __qualname__atributo é igual ao __name__atributo. Para classes, métodos e funções aninhadas, o __qualname__atributo contém um caminho pontilhado que leva ao objeto do nível superior do módulo.

É acessível a partir da própria definição de uma classe ou função, por exemplo:

class Foo:
    print(__qualname__)

irá imprimir efetivamente Foo. Você obterá o nome totalmente qualificado (excluindo o nome do módulo), então você pode querer dividi-lo no .caractere.

No entanto, não há como obter um controle real da classe que está sendo definida.

>>> class Foo:
...     print('Foo' in globals())
... 
False
Perna direita
fonte
7

EDIT: Sim, você pode; mas você tem que trapacear: o nome da classe em execução no momento está presente na pilha de chamadas e o tracebackmódulo permite que você acesse a pilha.

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

No entanto, eu não faria isso; Minha resposta original ainda é minha preferência como solução. Resposta original:

provavelmente a solução mais simples é usar um decorador, que é semelhante à resposta de Ned envolvendo metaclasses, mas menos poderoso (decoradores são capazes de magia negra, mas metaclasses são capazes de magia negra oculta antiga )

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

Eu acho que deveria ser assim:

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