Ottieni il nome della classe corrente?


102

Come ottengo il nome della classe in cui mi trovo attualmente?

Esempio:

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

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

A causa della natura del programma con cui mi sto interfacciando (vistrails), non posso usare __init__() per inizializzare input.

Risposte:


158

obj.__class__.__name__ ti darà il nome di qualsiasi oggetto, quindi puoi farlo:

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

Utilizzo:

>>> c = Clazz()
>>> c.getName()
'Clazz'

1
Perché non è questa la risposta accettata? EDIT: Ok l'ambito di OP non è interno, è a livello di classe.
KomodoDave

6
@KomodoDave, perché questo è sbagliato, anche nell'ambito del metodo. Quando si chiama getNameda una classe figlia, verrà visualizzato il nome della classe figlia. Allora diventa complicato se vuoi VERAMENTE la classe con cui lavori.
Kenet Jervet,

@KenetJervet Vuoi dire che quando chiami getNameda una classe genitore verrà emesso il nome della classe figlia? Va bene per averlo fatto notare.
KomodoDave

5
In termini OO, la soluzione (restituendo l'effettivo nome della classe figlia di runtime anche se il getName()metodo è definito in una superclasse) è corretta.
sxc731

22

All'interno del corpo di una classe, il nome della classe non è ancora definito, quindi non è disponibile. Non puoi semplicemente digitare il nome della classe? Forse hai bisogno di dire di più sul problema in modo che possiamo trovare una soluzione per te.

Creerei una metaclasse per fare questo lavoro per te. Viene invocato al momento della creazione della classe (concettualmente alla fine della classe: blocco) e può manipolare la classe che viene creata. Non l'ho provato:

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'

PER chiarire cosa sto cercando di fare: ho bisogno di creare e inizializzare una variabile di classe, 'input', al di fuori di un metodo . Ho un sacco di piccole classi, ognuna che deve chiamare "get_input" usando il nome della classe come parametro. Sto cercando di generalizzare questo in modo da non dover andare in ogni classe (ce ne saranno circa 100) e digitare il nome della classe.
Jonathan Ginsburg

OK, ho aggiornato la mia risposta con una metaclasse che dovrebbe aiutare.
Ned Batchelder

1
A cosa si riferisce MyTypela superriga in InputAssigningMetaclass?
A.Wan

16

Puoi accedervi dagli attributi privati ​​della classe:

cls_name = self.__class__.__name__

MODIFICARE:

Come detto da Ned Batcheler, questo non funzionerebbe nel corpo della classe, ma funzionerebbe in un metodo.


11

Introdotto PEP 3155__qualname__ , implementato in Python 3.3.

Per le funzioni e le classi di primo livello, l' __qualname__attributo è uguale __name__all'attributo. Per classi, metodi e funzioni annidate, l' __qualname__attributo contiene un percorso punteggiato che conduce all'oggetto dal livello superiore del modulo.

È accessibile dall'interno della definizione stessa di una classe o di una funzione, quindi ad esempio:

class Foo:
    print(__qualname__)

stamperà efficacemente Foo. Otterrai il nome completo (escluso il nome del modulo), quindi potresti volerlo dividere sul .personaggio.

Tuttavia, non è possibile ottenere un handle effettivo sulla classe in fase di definizione.

>>> class Foo:
...     print('Foo' in globals())
... 
False

7

EDIT: Sì, puoi; ma devi imbrogliare: il nome della classe attualmente in esecuzione è presente nello stack di chiamate e il tracebackmodulo ti consente di accedere allo stack.

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

Tuttavia, non lo farei; La mia risposta originale è ancora la mia preferenza come soluzione. Risposta originale:

probabilmente la soluzione più semplice è usare un decoratore, che è simile alla risposta di Ned che coinvolge le metaclassi, ma meno potente (i decoratori sono capaci di magia nera, ma le metaclassi sono capaci di magia nera antica e occulta )

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

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()

1

Penso che dovrebbe essere così:

    class foo():
        input = get_input(__qualname__)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.