Uzyskiwanie nazwy klasy wystąpienia?

1435

Jak znaleźć nazwę klasy, która utworzyła instancję obiektu w Pythonie, jeśli funkcja, z której to robię, jest klasą podstawową, z której wywodzi się klasa instancji?

Zastanawiałem się, czy moduł inspekcji mógł mi tutaj pomóc, ale wydaje się, że nie daje mi tego, czego chcę. Poza analizowaniem __class__członka, nie jestem pewien, jak uzyskać te informacje.

Dan
źródło
Co dokładnie „analizujesz” ze zmiennej klasy ?
sykora
1
nazwa najwyższego poziomu klasy, do której należy instancja (bez nazwy modułu itp.)
Dan.
Myślę, że przeciwnie byłoby znacznie trudniej (uzyskać klasę, w której zdefiniowano metodę / funkcję).
Alexey

Odpowiedzi:

1906

Próbowałeś już __name__atrybutu klasy? tj. type(x).__name__poda ci nazwę klasy, która moim zdaniem jest tym, czego chcesz.

>>> import itertools
>>> x = itertools.count(0)
>>> type(x).__name__
'count'

Jeśli nadal używasz języka Python 2, zauważ, że powyższa metoda działa tylko z klasami w nowym stylu (w Python 3+ wszystkie klasy są klasami „w nowym stylu”). Twój kod może używać klas w starym stylu. Następujące działa dla obu:

x.__class__.__name__
sykora
źródło
40
Niezwykle proste. Zastanawiam się, dlaczego dir(x.__class__)go nie wymieniono?
por.
43
Dlaczego warto korzystać __class__z tej typemetody? Tak: type(x).__name__. Czy odradzanie bezpośredniego wywoływania członków z podwójnym podkreśleniem nie jest odradzane? Nie widzę jednak sposobu na obejście __name__tego.
jpmc26
25
Musisz użyć __class__bezpośrednio, aby być kompatybilnym z klasami w starym stylu, ponieważ ich typ jest po prostu instance.
Quantum7
14
Jest to używane wystarczająco często w logowaniu, orm i kodzie frameworka, że ​​naprawdę powinna istnieć wbudowana nazwa typu (x) ... wymaganie od użytkownika spojrzenia na „odwagi” w celu uzyskania nazwy nie jest strasznie pytoniczne, IMO.
Erik Aronesty
5
@ErikAronesty,def typename(x): return type(x).__name__
sleblanc
388

Czy chcesz, aby nazwa klasy była łańcuchem?

instance.__class__.__name__
truppo
źródło
6
Lub instancja .__ class__, aby uzyskać obiekt klasy: D
Pencilcheck
8
Czy bezpiecznie jest używać właściwości podwójnego podkreślenia?
Eduard Luca,
5
@EduardLuca dlaczego nie byłoby bezpieczne? Wbudowane właściwości wykorzystują podkreślenia, aby nie powodowały żadnego konfliktu z
pisanym
3
Wiem, że pojedyncze podkreślenia oznaczają / sugerują, że metoda / właściwość powinna być prywatna (chociaż tak naprawdę nie można zaimplementować prywatnych metod w Pythonie AFAIK), i zastanawiałem się, czy tak nie jest w przypadku (niektórych) podwójnych podkreśleń.
Eduard Luca,
28
@EduardLuca Podwójne podkreślenia tylko na początku są podobne do pojedynczego podkreślenia na początku, ale jeszcze bardziej „prywatne” (patrz „mangling python name”). Podwójne podkreślenia na początku i na końcu są różne - są zarezerwowane dla Pythona i nie są prywatne (np. Magiczne metody, takie jak __init__ i __add__).
Leagsaidh Gordon,
100

rodzaj() ?

>>> class A(object):
...    def whoami(self):
...       print type(self).__name__
...
>>>
>>> class B(A):
...    pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>
GHZ
źródło
jest to to samo, co członek klasy , ale muszę ręcznie przeanalizować ten wynik, co jest nieco denerwujące ...
Dan
8
Ten mi się podoba. W ten sposób w klasie bazowej możliwe jest uzyskanie nazwy podklasy.
joctee
6
lub self.__class__.__name__zamiast type(self).__name__uzyskać takie samo zachowanie. Chyba że istnieje type()funkcja, o której nie wiem?
andreb
2
Jeśli używasz type(item)na elemencie listy wynik będzie <type 'instance'>natomiast item.__class__.__name__posiada nazwę klasy.
Grochni
1
Myślę, że problem, o którym wspomina @Grochni, dotyczy tylko niektórych klas w Pythonie 2.x, patrz tutaj: stackoverflow.com/questions/6666856/…
Nate CK
43
class A:
  pass

a = A()
str(a.__class__)

Powyższy przykładowy kod (po wprowadzeniu do interaktywnego interpretera) wygeneruje, '__main__.A'w przeciwieństwie do tego, 'A'który zostanie wygenerowany, jeśli __name__atrybut zostanie wywołany. Po prostu przekazując wynik A.__class__do strkonstruktora, parsowanie jest obsługiwane. Możesz jednak użyć następującego kodu, jeśli chcesz czegoś bardziej wyraźnego.

"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)

Takie zachowanie może być preferowane, jeśli masz klasy o tej samej nazwie zdefiniowane w oddzielnych modułach.

Przykładowy kod podany powyżej został przetestowany w Pythonie 2.7.5.

Jonathan
źródło
Testowane w wersji 2.6.6. Nadal działa dobrze.
Hamlett,
29
type(instance).__name__ != instance.__class__.__name  #if class A is defined like
class A():
   ...

type(instance) == instance.__class__                  #if class A is defined like
class A(object):
  ...

Przykład:

>>> class aclass(object):
...   pass
...
>>> a = aclass()
>>> type(a)
<class '__main__.aclass'>
>>> a.__class__
<class '__main__.aclass'>
>>>
>>> type(a).__name__
'aclass'
>>>
>>> a.__class__.__name__
'aclass'
>>>


>>> class bclass():
...   pass
...
>>> b = bclass()
>>>
>>> type(b)
<type 'instance'>
>>> b.__class__
<class __main__.bclass at 0xb765047c>
>>> type(b).__name__
'instance'
>>>
>>> b.__class__.__name__
'bclass'
>>>
Prasath
źródło
5
Dotyczy to tylko starego Pythona 2.x. W wersji 3.x bclass () przekształciłby się w bclass (obiekt). I nawet wtedy nowe klasy pojawiły się w Pythonie 2.2.
alcalde,
16

Dobre pytanie.

Oto prosty przykład oparty na GHZ, który może komuś pomóc:

>>> class person(object):
        def init(self,name):
            self.name=name
        def info(self)
            print "My name is {0}, I am a {1}".format(self.name,self.__class__.__name__)
>>> bob = person(name='Robert')
>>> bob.info()
My name is Robert, I am a person
RyanN
źródło
13

Alternatywnie możesz użyć classmethoddekoratora:

class A:
    @classmethod
    def get_classname(cls):
        return cls.__name__

    def use_classname(self):
        return self.get_classname()

Zastosowanie :

>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'
Jurij Rabeshko
źródło
10

Oprócz __name__zdobycia specjalnego atrybutu, możesz potrzebować kwalifikowanej nazwy dla danej klasy / funkcji. Odbywa się to poprzez chwytanie typów __qualname__.

W większości przypadków będą one dokładnie takie same, ale w przypadku zagnieżdżonych klas / metod różnią się one uzyskanymi wynikami. Na przykład:

class Spam:
    def meth(self):
        pass
    class Bar:
        pass

>>> s = Spam()
>>> type(s).__name__ 
'Spam'
>>> type(s).__qualname__
'Spam'
>>> type(s).Bar.__name__       # type not needed here
'Bar'
>>> type(s).Bar.__qualname__   # type not needed here 
'Spam.Bar'
>>> type(s).meth.__name__
'meth'
>>> type(s).meth.__qualname__
'Spam.meth'

Ponieważ szukasz introspekcji, zawsze warto to rozważyć.

Dimitris Fasarakis Hilliard
źródło
2
Należy zauważyć, że __qualname__dotyczy Python 3.3+
FireAphis 30.01.2018
10
I unikałbym nazywania czegokolwiek w moim oprogramowaniu „met”.
Bobort
Podobne wyjaśnienie dla __qualname__vs __name__: stackoverflow.com/questions/58108488/what-is-qualname-in-python
ti7
0

Aby uzyskać instancję nazwa klasy:

type(instance).__name__

lub

instance.__class__.__name__

oba są takie same

v.babak
źródło