Obtenir le nom de classe complet d'un objet en Python
-
19-09-2019 - |
Question
Pour des raisons d'exploitation, je veux récupérer le nom de classe complet d'un objet Python. (Je veux dire avec qualifié le nom de classe, y compris le paquet et le nom du module.)
Je sais x.__class__.__name__
, mais est-il une méthode simple pour obtenir le package et le module?
La solution
Avec le programme suivant
#! /usr/bin/env python
import foo
def fullname(o):
# o.__module__ + "." + o.__class__.__qualname__ is an example in
# this context of H.L. Mencken's "neat, plausible, and wrong."
# Python makes no guarantees as to whether the __module__ special
# attribute is defined, so we take a more circumspect approach.
# Alas, the module name is explicitly excluded from __qualname__
# in Python 3.
module = o.__class__.__module__
if module is None or module == str.__class__.__module__:
return o.__class__.__name__ # Avoid reporting __builtin__
else:
return module + '.' + o.__class__.__name__
bar = foo.Bar()
print fullname(bar)
et Bar
définie comme
class Bar(object):
def __init__(self, v=42):
self.val = v
la sortie est
$ ./prog.py
foo.Bar
Autres conseils
Les réponses fournies ne traitent pas des classes imbriquées. Bien que ce n'est pas disponible jusqu'à Python 3.3 ( PEP 3155 ), vous voulez vraiment utiliser __qualname__
de la classe. Finalement (3.4? PEP 395 ), __qualname__
existera également des modules pour traiter les cas où le module est renommé (quand il est renommé __main__
).
Pensez à utiliser le module inspect
qui a des fonctions comme getmodule
qui pourrait être ce que recherchent:
>>>import inspect
>>>import xml.etree.ElementTree
>>>et = xml.etree.ElementTree.ElementTree()
>>>inspect.getmodule(et)
<module 'xml.etree.ElementTree' from
'D:\tools\python2.5.2\lib\xml\etree\ElementTree.pyc'>
Voici une excellente réponse basée sur Greg Bacon, mais avec quelques contrôles supplémentaires:
__module__
peut être None
(selon les docs), et aussi pour un type comme str
il peut être __builtin__
(que vous pourriez ne pas vouloir apparaître dans les journaux ou autre). Les contrôles suivants pour ces deux possibilités:
def fullname(o):
module = o.__class__.__module__
if module is None or module == str.__class__.__module__:
return o.__class__.__name__
return module + '.' + o.__class__.__name__
(Il pourrait y avoir une meilleure façon de vérifier __builtin__
. Ce qui précède repose simplement sur le fait que str est toujours disponible, et son module est toujours __builtin__
)
__module__
ferait l'affaire.
Essayez:
>>> import re
>>> print re.compile.__module__
re
Ce site suggère que __package__
pourrait fonctionner pour Python 3.0; Cependant, les exemples donnés, il ne fonctionnera pas sous mon Python 2.5.2 console.
Ceci est un hack mais je soutiens 2.6 et juste besoin de quelque chose simple:
>>> from logging.handlers import MemoryHandler as MH
>>> str(MH).split("'")[1]
'logging.handlers.MemoryHandler'
Certaines personnes (par exemple https://stackoverflow.com/a/16763814/5766934 ) en faisant valoir que __qualname__
est mieux que __name__
.
Voici un exemple qui montre la différence:
$ cat dummy.py
class One:
class Two:
pass
$ python3.6
>>> import dummy
>>> print(dummy.One)
<class 'dummy.One'>
>>> print(dummy.One.Two)
<class 'dummy.One.Two'>
>>> def full_name_with_name(klass):
... return f'{klass.__module__}.{klass.__name__}'
>>> def full_name_with_qualname(klass):
... return f'{klass.__module__}.{klass.__qualname__}'
>>> print(full_name_with_name(dummy.One)) # Correct
dummy.One
>>> print(full_name_with_name(dummy.One.Two)) # Wrong
dummy.Two
>>> print(full_name_with_qualname(dummy.One)) # Correct
dummy.One
>>> print(full_name_with_qualname(dummy.One.Two)) # Correct
dummy.One.Two
Remarque, cela fonctionne aussi correctement pour buildins:
>>> print(full_name_with_qualname(print))
builtins.print
>>> import builtins
>>> builtins.print
<built-in function print>
Pour python3.7 J'utilise:
".".join([obj.__module__, obj.__name__])
Obtenir:
package.subpackage.ClassName
Depuis l'intérêt de ce sujet est d'obtenir les noms qualifiés, voici un écueil qui se produit lors de l'utilisation des importations par rapport avec le module principal existant dans le même paquet. Par exemple, avec la configuration du module ci-dessous:
$ cat /tmp/fqname/foo/__init__.py
$ cat /tmp/fqname/foo/bar.py
from baz import Baz
print Baz.__module__
$ cat /tmp/fqname/foo/baz.py
class Baz: pass
$ cat /tmp/fqname/main.py
import foo.bar
from foo.baz import Baz
print Baz.__module__
$ cat /tmp/fqname/foo/hum.py
import bar
import foo.bar
Voici la sortie montrant le résultat de l'importation du même module différemment:
$ export PYTHONPATH=/tmp/fqname
$ python /tmp/fqname/main.py
foo.baz
foo.baz
$ python /tmp/fqname/foo/bar.py
baz
$ python /tmp/fqname/foo/hum.py
baz
foo.baz
Lorsque les importations de bourdonnement de barres en utilisant un chemin relatif, bar Sées Baz.__module__
comme juste « baz », mais dans la deuxième importation qui utilise le nom complet, bar voit la même chose que « foo.baz ».
Si vous persistez les noms qualifiés quelque part, il est préférable d'éviter les importations relatives à ces classes.
Aucune des réponses ici travaillé pour moi. Dans mon cas, j'utilisais Python 2.7 et je savais que je serais seulement travailler avec des classes de Newstyle object
.
def get_qualified_python_name_from_class(model):
c = model.__class__.__mro__[0]
name = c.__module__ + "." + c.__name__
return name