2011-08-04 20 views
66

Jak uzyskać nazwę klasy, w której aktualnie jestem?Uzyskaj nazwę aktualnej klasy?

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 Mam współpracujący z (vistrails), nie mogę używać __init__() zainicjować input.

Odpowiedz

18

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

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

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

do wyjaśnienia, co próbuję zrobić: trzeba utworzyć i zainicjować zmienną klasy, 'input', ** poza metody **. Mam kilka małych klas, z których każda musi wywoływać "get_input", używając jako nazwy parametru swojej klasy. Próbuję to uogólnić, więc nie muszę iść do każdej klasy (będzie ich około 100) i wpisać nazwę klasy. –

+0

OK, zaktualizowałem swoją odpowiedź za pomocą metaklasu, który powinien pomóc. –

+0

Co oznacza 'MyType' w linii' super' w 'InputAssigningMetaclass'? –

12

można uzyskać do niego dostęp przez klasę atrybutów private:

cls_name = self.__class__.__name__ 

EDIT:

Jak powiedział przez Ned Batcheler, to nie będzie działać w ciele klasy, ale byłoby to w metodzie.

99

obj.__class__.__name__ będzie Ci żadnej nazwy obiektów, więc można to zrobić:

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

Zastosowanie:

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

Dlaczego nie jest to zaakceptowana odpowiedź? EDYCJA: Zakres OK OK nie jest wewnętrzny, jest na poziomie klasy. – KomodoDave

+1

@KomodoDave, ponieważ jest to błędne, nawet w zakresie metody. Wywołanie funkcji 'getName' z klasy potomnej spowoduje wyświetlenie nazwy klasy potomnej. Wtedy staje się trudne, jeśli NAPRAWDĘ chcesz mieć zajęcia, z którymi pracujesz. –

+0

@KenetJervet Masz na myśli, gdy wywołasz 'getName' z klasy _parent_, która wypisze nazwę klasy potomnej? Ok, za wskazanie tego. – KomodoDave

7

EDIT: Tak, to możliwe; ale musisz oszukać: aktualnie działająca nazwa klasy jest obecna na stosie wywołań, a moduł traceback 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 oryginalna odpowiedź nadal jest moją własną preferencją jako rozwiązaniem. Odpowiedź oryginalny:

prawdopodobnie bardzo Najprostszym rozwiązaniem jest użycie dekorator, który jest podobny do odpowiedzi Neda udziałem metaclasses, ale mniej wydajne (dekoratorów są zdolne do czarnej magii, ale metaclasses są zdolne starożytnych, 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()