web-dev-qa-db-fra.com

Obtenir le nom de classe complet d'un objet en Python

À des fins de journalisation, je souhaite récupérer le nom de classe complet d'un objet Python. (Par qualifié complet, je veux dire le nom de la classe, y compris le nom du paquet et du module.)

Je connais x.__class__.__name__, mais existe-t-il une méthode simple pour obtenir le paquet et le module?

102
Hanno S.

Avec le programme suivant

#! /usr/bin/env python

import foo

def fullname(o):
  # o.__module__ + "." + o.__class__.__qualis 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__.__ # Avoid reporting __builtin__
  else:
    return module + '.' + o.__class__.__name__

bar = foo.Bar()
print fullname(bar)

et Bar défini comme

class Bar(object):
  def __init__(self, v=42):
    self.val = v

la sortie est

$ ./prog.py
foo.Bar
112
Greg Bacon

Les réponses fournies ne traitent pas des classes imbriquées. Bien qu'il ne soit pas disponible avant Python 3.3 ( PEP 3155 ), vous voulez vraiment utiliser __qualname__ de la classe. Finalement (3.4? PEP 395 ), __qualname__ existera également pour les modules afin de traiter les cas dans lesquels le module est renommé (c'est-à-dire lorsqu'il est renommé en __main__).

23
Nathan Binkert

Pensez à utiliser le module inspect qui comporte des fonctions telles que getmodule qui pourraient être ce que vous recherchez:

>>>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'>
21
Tendayi Mawushe

En voici une basée sur l'excellente réponse de Greg Bacon, mais avec quelques vérifications supplémentaires:

__module__ peut être None (selon la documentation), et également pour un type comme str, il peut s'agir de __builtin__ (que vous ne souhaitez peut-être pas voir apparaître dans les journaux ou autre). Les contrôles suivants vérifient 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 existe peut-être un meilleur moyen de vérifier __builtin__. Ce qui précède repose simplement sur le fait que str est toujours disponible et que son module est toujours __builtin__.)

13
MB.

__module__ ferait l'affaire.

Essayer:

>>> import re
>>> print re.compile.__module__
re

Ce site suggère que __package__ pourrait fonctionner pour Python 3.0; Cependant, les exemples donnés ne fonctionneront pas sous ma console Python 2.5.2.

9
Adam Matan

C'est un hack mais je supporte la 2.6 et j'ai juste besoin de quelque chose de simple:

>>> from logging.handlers import MemoryHandler as MH
>>> str(MH).split("'")[1]

'logging.handlers.MemoryHandler'
5
Gringo Suave

Pour python3.7 j'utilise:

".".join([obj.__module__, obj.__name__])

Obtenir:

package.subpackage.ClassName
4

Étant donné que l’intérêt de cette rubrique est d’obtenir des noms complets, voici un écueil qui se produit lors de l’utilisation des importations relatives avec le module principal existant dans le même package. Par exemple, avec la configuration de 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 hum importe bar en utilisant le chemin relatif, bar voit Baz.__module__ comme étant simplement "baz", mais dans la seconde importation qui utilise le nom complet, bar voit la même chose que "foo.baz".

Si vous persistez les noms entièrement qualifiés quelque part, il est préférable d'éviter les importations relatives pour ces classes.

2
haridsv

Certaines personnes (par exemple https://stackoverflow.com/a/16763814/5766934 ) soutiennent que __qualname__ est supérieur à __name__. Voici un exemple montrant 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

Notez que cela fonctionne aussi correctement pour les buildins:

>>> print(full_name_with_qualname(print))
builtins.print
>>> import builtins
>>> builtins.print
<built-in function print>
1

Aucune des réponses ici n'a fonctionné pour moi. Dans mon cas, j'utilisais Python 2.7 et je savais que je ne travaillerais qu'avec des classes newstyle object

def get_qualified_python_name_from_class(model):
    c = model.__class__.__mro__[0]
    name = c.__module__ + "." + c.__name__
    return name
0
P. Myer Nore