Chcesz poznać nazwę bieżącej klasy?


102

Jak uzyskać nazwę klasy, w której obecnie się uczę?

Przykład:

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

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

Ze względu na charakter programu, z którym się łączę (vistrails), nie mogę go użyć __init__()do inicjalizacji input.

Odpowiedzi:


158

obj.__class__.__name__ poda Ci dowolną nazwę obiektu, więc możesz to zrobić:

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

Stosowanie:

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

1
Dlaczego nie jest to akceptowana odpowiedź? EDYCJA: Ok, zakres OP nie jest wewnętrzny, jest na poziomie klasy.
KomodoDave

6
@KomodoDave, ponieważ jest to błąd, nawet w zakresie metody. Kiedy dzwonisz getNamez klasy podrzędnej, wyświetli nazwę klasy podrzędnej. To staje się trudne, jeśli NAPRAWDĘ chcesz mieć klasę, z którą pracujesz.
Kenet Jervet

@KenetJervet Czy masz na myśli, że wywołanie getNamez klasy nadrzędnej spowoduje wyświetlenie nazwy klasy podrzędnej? Ok za wskazanie tego.
KomodoDave

5
W terminach OO rozwiązanie (zwracanie rzeczywistej nazwy klasy getName()potomnej w czasie wykonywania, nawet jeśli metoda jest zdefiniowana w nadklasie) jest poprawne.
sxc731

22

W treści klasy nazwa klasy nie jest jeszcze zdefiniowana, więc nie jest dostępna. Czy nie możesz po prostu wpisać nazwy klasy? Może chcesz powiedzieć więcej o problemie, abyśmy mogli znaleźć dla Ciebie rozwiązanie.

Utworzyłbym metaklasę, aby wykonać tę pracę za Ciebie. Jest wywoływana w czasie tworzenia klasy (koncepcyjnie na samym końcu klasy: blok) i może manipulować tworzoną klasą. Nie testowałem tego:

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'

Aby wyjaśnić, co próbuję zrobić: Muszę utworzyć i zainicjować zmienną klasy, „wejście”, poza metodą . Mam kilka małych klas, z których każda musi wywoływać „get_input”, używając nazwy swojej klasy jako parametru. Próbuję to uogólniać, więc nie muszę iść na każde zajęcia (będzie ich około 100) i wpisywać nazwy zajęć.
Jonathan Ginsburg

OK, zaktualizowałem moją odpowiedź metaklasą, która powinna pomóc.
Ned Batchelder

1
Czego dotyczy MyTypew superwierszu InputAssigningMetaclass?
A. Wan

16

Możesz uzyskać do niego dostęp poprzez prywatne atrybuty klasy:

cls_name = self.__class__.__name__

EDYTOWAĆ:

Jak powiedziano Ned Batcheler, to nie zadziała w treści klasy, ale zadziała w metodzie.


11

Wprowadzono PEP 3155__qualname__ , który został zaimplementowany w Pythonie 3.3.

W przypadku funkcji i klas najwyższego poziomu __qualname__atrybut jest równy __name__atrybutowi. W przypadku zagnieżdżonych klas, metod i funkcji zagnieżdżonych __qualname__atrybut zawiera kropkowaną ścieżkę prowadzącą do obiektu z najwyższego poziomu modułu.

Jest dostępny z poziomu samej definicji klasy lub funkcji, na przykład:

class Foo:
    print(__qualname__)

efektywnie wydrukuje Foo. Otrzymasz w pełni kwalifikowaną nazwę (z wyłączeniem nazwy modułu), więc możesz podzielić ją na .postać.

Jednak nie ma sposobu, aby uzyskać faktyczne dojście do definiowanej klasy.

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

7

EDYCJA: Tak, możesz; ale musisz oszukiwać: nazwa aktualnie uruchomionej klasy jest obecna na stosie wywołań, a tracebackmoduł umożliwia dostęp do stosu.

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

Jednak nie zrobiłbym tego; Moja pierwotna odpowiedź to nadal moje własne preferencje jako rozwiązanie. Oryginalna odpowiedź:

prawdopodobnie najprostszym rozwiązaniem jest użycie dekoratora, który jest podobny do odpowiedzi Neda obejmującego metaklasy, ale mniej potężny (dekoratorzy są zdolni do czarnej magii, ale metaklasy są zdolne do starożytnej, okultystycznej czarnej magii)

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

Myślę, że powinno być tak:

    class foo():
        input = get_input(__qualname__)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.