Obtenir le nom de classe d'une instance?

1438

Comment puis-je trouver un nom de classe qui a créé une instance d'un objet en Python si la fonction dont je fais cela est la classe de base dont la classe de l'instance a été dérivée?

Je pensais que le module d'inspection m'aurait peut-être aidé ici, mais il ne semble pas me donner ce que je veux. Et à moins d'analyser le __class__membre, je ne sais pas comment obtenir ces informations.

Dan
la source
Que analysez-vous exactement à partir de la variable de classe ?
sykora
1
le nom de niveau supérieur de la classe à laquelle l'instance appartient (sans nom de module, etc ...)
Dan
Je pense que le contraire serait beaucoup plus difficile (pour obtenir la classe dans laquelle la méthode / fonction est définie).
Alexey

Réponses:

1910

Avez-vous essayé l' __name__attribut de la classe? c'est-à type(x).__name__- dire vous donnera le nom de la classe, qui je pense est ce que vous voulez.

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

Si vous utilisez toujours Python 2, notez que la méthode ci-dessus fonctionne uniquement avec les classes de nouveau style (dans Python 3+ toutes les classes sont des classes de "nouveau style"). Votre code peut utiliser certaines classes à l'ancienne. Les travaux suivants pour les deux:

x.__class__.__name__
sykora
la source
41
Étonnamment simple. Je dir(x.__class__)me demande pourquoi ne l' énumère pas?
cfi
43
Pourquoi utiliser __class__la typeméthode? Comme ceci: type(x).__name__. N'est-il pas directement déconseillé d'appeler des membres à double soulignement? __name__Cependant, je ne vois pas comment contourner l'utilisation .
jpmc26
25
Vous devez utiliser __class__directement pour être compatible avec les classes à l'ancienne, car leur type est juste instance.
Quantum7
14
Ceci est utilisé assez souvent dans la journalisation, orm et le code de framework pour qu'il devrait vraiment y avoir un nom de type intégré (x) ... obligeant un utilisateur à regarder les "tripes" pour obtenir un nom n'est pas terriblement pythonique, IMO.
Erik Aronesty
5
@ErikAronesty,def typename(x): return type(x).__name__
sleblanc
392

Voulez-vous que le nom de la classe soit une chaîne?

instance.__class__.__name__
truppo
la source
6
Ou par exemple .__ class__ pour obtenir l'objet de classe: D
Pencilcheck
8
Est-il sûr d'utiliser des propriétés de soulignement double?
Eduard Luca
5
@EduardLuca pourquoi ne serait-il pas sûr? Les propriétés intégrées utilisent des traits de soulignement afin de ne pas créer de conflit avec le code que vous écrivez
JC Rocamonde
3
Eh bien, je sais que les traits de soulignement simples signifient / suggèrent que la méthode / propriété devrait être privée (bien que vous ne puissiez pas vraiment implémenter des méthodes privées dans Python AFAIK), et je me demandais si ce n'était pas le cas avec (certains) doubles soulignements aussi.
Eduard Luca
28
@EduardLuca Les traits de soulignement doubles au début seulement sont similaires à un seul trait de soulignement au début, mais encore plus «privés» (recherchez «mangling de nom de python»). Les doubles soulignements au début et à la fin sont différents - ceux-ci sont réservés pour python et ne sont pas privés (par exemple les méthodes magiques comme __init__ et __add__).
Leagsaidh Gordon
101

type ()?

>>> class A(object):
...    def whoami(self):
...       print type(self).__name__
...
>>>
>>> class B(A):
...    pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>
GHZ
la source
c'est la même chose que le membre de la classe , mais je dois analyser ce résultat à la main, ce qui est un peu ennuyeux ...
Dan
8
J'aime celui la. De cette façon, il est possible dans une classe de base d'obtenir le nom de la sous-classe.
joctee
6
ou self.__class__.__name__au lieu d' type(self).__name__obtenir le même comportement. À moins qu'il y ait quelque chose que la type()fonction fait que je ne sache pas?
andreb
2
Si vous utilisez type(item)un élément de liste, le résultat sera alors <type 'instance'>que item.__class__.__name__contient le nom de la classe.
Grochni
1
Je pense que le problème mentionné par @Grochni n'est pertinent que pour certaines classes de Python 2.x, voir ici: stackoverflow.com/questions/6666856/…
Nate CK
43
class A:
  pass

a = A()
str(a.__class__)

L'exemple de code ci-dessus (lorsqu'il est entré dans l'interpréteur interactif) produira '__main__.A'par opposition à celui 'A'qui est produit si l' __name__attribut est appelé. En passant simplement le résultat de A.__class__au strconstructeur, l'analyse est gérée pour vous. Cependant, vous pouvez également utiliser le code suivant si vous souhaitez quelque chose de plus explicite.

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

Ce comportement peut être préférable si vous avez des classes avec le même nom définies dans des modules séparés.

L'exemple de code fourni ci-dessus a été testé en Python 2.7.5.

Jonathan
la source
Testé en 2.6.6. Fonctionne toujours bien.
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):
  ...

Exemple:

>>> 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
la source
5
Cela ne vaut que pour l'ancien Python 2.x. Dans 3.x, bclass () se résoudrait en bclass (object). Et même alors, de nouvelles classes sont apparues dans Python 2.2.
alcalde
16

Bonne question.

Voici un exemple simple basé sur les GHZ qui pourrait aider quelqu'un:

>>> 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
la source
13

Vous pouvez également utiliser le classmethoddécorateur:

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

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

Utilisation :

>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'
Yurii Rabeshko
la source
10

En plus de saisir l' __name__attribut spécial , vous pourriez avoir besoin du nom qualifié pour une classe / fonction donnée. Cela se fait en saisissant les types __qualname__.

Dans la plupart des cas, ceux-ci seront exactement les mêmes, mais, lorsqu'ils traitent avec des classes / méthodes imbriquées, elles diffèrent dans la sortie que vous obtenez. Par exemple:

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'

Puisque l'introspection est ce que vous recherchez, c'est toujours ce que vous voudrez peut-être considérer.

Dimitris Fasarakis Hilliard
la source
2
Il convient de noter que __qualname__c'est pour Python 3.3+
FireAphis
10
Et j'éviterais de nommer quoi que ce soit dans mon logiciel "meth".
Bobort
Explication connexe pour __qualname__vs __name__: stackoverflow.com/questions/58108488/what-is-qualname-in-python
ti7
0

Pour obtenir le nom de classe de l'instance:

type(instance).__name__

ou

instance.__class__.__name__

les deux sont les mêmes

v.babak
la source