Holen vollständig qualifizierten Klassennamen eines Objekts in Python
-
19-09-2019 - |
Frage
Für Protokollierungszwecke möchte ich den vollständig qualifizierten Klassennamen eines Python-Objekt abzurufen. (Mit voll qualifizieren meine ich die Klassennamen einschließlich der Verpackung und Modulnamen.)
Ich weiß, über x.__class__.__name__
, aber gibt es eine einfache Methode, um das Paket und Modul zu bekommen?
Lösung
Mit dem folgenden Programm
#! /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)
und Bar
definiert als
class Bar(object):
def __init__(self, v=42):
self.val = v
ist der Ausgang
$ ./prog.py
foo.Bar
Andere Tipps
Die bereitgestellten Antworten Sie befasst sich nicht mit verschachtelten Klassen. Obwohl es bis Python nicht verfügbar ist 3.3 ( PEP 3155 ), wollen Sie wirklich verwenden __qualname__
der Klasse. Schließlich (3.4? PEP 395 ), __qualname__
auch für Module existieren, zu beschäftigen Fälle, in denen das Modul umbenannt wird (dh, wenn es um __main__
umbenannt wird).
Betrachten Sie das inspect
Modul, das Funktionen wie getmodule
hat das, was suchen werden:
>>>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'>
Hier ist ein auf Basis von Greg Bacons ausgezeichnete Antwort, aber mit ein paar zusätzlichen Kontrollen:
__module__
kann (nach der docs) None
wird, und auch für einen Typen wie str
kann es __builtin__
werden (die Sie nicht in Protokollen erscheinen möchten oder was auch immer). Die folgenden Kontrollen für beide dieser Möglichkeiten:
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__
(Es könnte eine bessere Möglichkeit für __builtin__
zu überprüfen. Die oben verlassen sich nur auf der Tatsache, dass str immer verfügbar ist, und sein Modul ist immer __builtin__
)
__module__
würde den Trick tun.
Versuchen:
>>> import re
>>> print re.compile.__module__
re
Diese Seite dass __package__
schlägt vor, für Python 3.0 funktionieren könnte; Doch angesichts der Beispiele wird es nicht unter meiner Python 2.5.2 Konsole arbeiten.
Dies ist ein Hack, aber ich bin 2.6 unterstützen und braucht nur etwas einfach:
>>> from logging.handlers import MemoryHandler as MH
>>> str(MH).split("'")[1]
'logging.handlers.MemoryHandler'
Einige Leute (zB https://stackoverflow.com/a/16763814/5766934 ), dass __qualname__
streiten ist besser als __name__
.
Hier ist ein Beispiel, das den Unterschied zeigt:
$ 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
Beachten Sie, es funktioniert auch richtig für buildins:
>>> print(full_name_with_qualname(print))
builtins.print
>>> import builtins
>>> builtins.print
<built-in function print>
Für python3.7 ich benutze:
".".join([obj.__module__, obj.__name__])
Ankommen:
package.subpackage.ClassName
Da das Interesse an diesem Thema voll qualifizierte Namen zu bekommen ist, ist hier eine Gefahr, die auftritt, wenn die relativen Einfuhren mit zusammen mit dem Hauptmodul im selben Paket vorhanden ist. Zum Beispiel mit den folgenden Moduleinstellungen:
$ 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
Hier ist die Ausgabe das Ergebnis des Imports das gleiche Modul zeigt anders:
$ 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
Wenn hum Importe bar relativen Pfad, Bar sieht als nur "baz" Baz.__module__
, aber in dem zweiten Import, die vollständigen Namen verwendet, eine Bar sieht das gleiche wie "foo.baz".
Wenn Sie die vollständig qualifizierten Namen irgendwo sind persistierende, es besser ist, relativ Importe für diese Klassen zu vermeiden.
Keine der Antworten hier für mich gearbeitet. In meinem Fall war ich Python 2.7 und wusste, dass ich mit nur mit newstyle object
Klassen arbeiten würde.
def get_qualified_python_name_from_class(model):
c = model.__class__.__mro__[0]
name = c.__module__ + "." + c.__name__
return name