Obtener el nombre completo de la clase de un objeto en Python
-
19-09-2019 - |
Pregunta
Para propósitos de registro Quiero recuperar el nombre de clase completo de un objeto de Python. (Con completo me refiero al nombre de la clase que incluye el paquete y el nombre del módulo.)
Yo sé de x.__class__.__name__
, pero ¿hay un método sencillo para obtener el paquete y módulo?
Solución
Con el siguiente programa
#! /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)
y Bar
define como
class Bar(object):
def __init__(self, v=42):
self.val = v
la salida es
$ ./prog.py
foo.Bar
Otros consejos
Las respuestas proporcionadas no se ocupan de clases anidadas. Aunque no está disponible hasta Python 3.3 ( PEP 3155 ), que realmente desea utilizar __qualname__
de la clase. Finalmente (3.4? PEP 395 ), __qualname__
también existirá para los módulos para hacer frente a los casos en que se cambia el nombre del módulo (es decir, cuando se cambia a __main__
).
Considere el uso del módulo inspect
que tiene funciones como getmodule
que podría ser lo que buscas:
>>>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'>
Esto es una basada en la excelente respuesta de Greg Bacon, pero con un par de comprobaciones adicionales:
__module__
puede None
(de acuerdo con los documentos), y también para un tipo como str
se puede __builtin__
(que puede que no desee que aparece en los registros o lo que sea). Los siguientes controles para ambos esas posibilidades:
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__
(Puede haber una mejor manera de comprobar si hay __builtin__
. Lo anterior simplemente se basa en el hecho de que str siempre está disponible, y su módulo es siempre __builtin__
)
__module__
haría el truco.
Probar:
>>> import re
>>> print re.compile.__module__
re
Este sitio sugiere que __package__
podría funcionar para Python 3.0; Sin embargo, los ejemplos dados no trabajarán bajo mi consola Python 2.5.2.
Este es un truco, pero estoy apoyando 2,6 y sólo necesita algo simple:
>>> from logging.handlers import MemoryHandler as MH
>>> str(MH).split("'")[1]
'logging.handlers.MemoryHandler'
Algunas personas (por ejemplo, https://stackoverflow.com/a/16763814/5766934 ) argumentando que es mejor __qualname__
que __name__
.
Aquí es un ejemplo que muestra la diferencia:
$ 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
Tenga en cuenta, que también funciona correctamente para buildins:
>>> print(full_name_with_qualname(print))
builtins.print
>>> import builtins
>>> builtins.print
<built-in function print>
Para python3.7 que utilizo:
".".join([obj.__module__, obj.__name__])
Cómo:
package.subpackage.ClassName
Dado que el interés de este tema es conseguir nombres completos, aquí es una trampa que se produce cuando se utilizan las importaciones en relación con el módulo principal existente en el mismo paquete. Por ejemplo, con la configuración del módulo a continuación:
$ 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
Aquí está la salida que muestra el resultado de la importación de un mismo módulo de forma diferente:
$ 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
Cuando las importaciones de barras de zumbido utilizando una ruta relativa, bar Baz.__module__
ve simplemente como "Baz", pero en la segunda importación que utiliza el nombre completo, la barra ve lo mismo que "foo.baz".
Si está persistiendo los nombres totalmente calificados en alguna parte, es mejor evitar las importaciones en relación a esas clases.
Ninguna de las respuestas aquí trabajado para mí. En mi caso, yo estaba usando Python 2.7 y sabía que sólo estaría trabajando con clases object
newstyle.
def get_qualified_python_name_from_class(model):
c = model.__class__.__mro__[0]
name = c.__module__ + "." + c.__name__
return name