Uzyskaj w pełni kwalifikowaną nazwę klasy obiektu w Pythonie


136

Do celów rejestrowania chcę pobrać w pełni kwalifikowaną nazwę klasy obiektu Pythona. (W pełni kwalifikowane mam na myśli nazwę klasy, w tym nazwę pakietu i modułu).

Wiem o tym x.__class__.__name__, ale czy istnieje prosty sposób na pobranie pakietu i modułu?

Odpowiedzi:


147

Z następującym programem

#! /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)

i Barzdefiniowany jako

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

wyjście jest

$ ./prog.py
foo.Bar

2
Wydaje się, że zwraca moduł, w którym zdefiniowano pręt, a nie tam, gdzie zdefiniowano pasek. Jeśli celem rejestrowania jest dokładne poznanie rodzaju obiektu, to nie wydaje się to pomagać.
Mark E. Haase

Czy o.__class__.__module__kiedykolwiek różni się od o.__module__?
larsks


1
Gorąco polecam ".".join([o.__module__, o.__name__])dla Pythona3
Piotr Pęczek

Czasami nie działa:AttributeError: 'AttributeError' object has no attribute '__module__'
Hendy Irawan

38

Podane odpowiedzi nie dotyczą klas zagnieżdżonych. Chociaż nie jest dostępna przed wersją Python 3.3 ( PEP 3155 ), naprawdę chcesz użyć __qualname__tej klasy. Ostatecznie (3.4? PEP 395 ) __qualname__będzie również istnieć dla modułów do obsługi przypadków, w których nazwa modułu zostanie zmieniona (tj. Kiedy zostanie zmieniona na __main__).


3
Jeśli korzystasz z github.com/wbolster/qualname , możesz uzyskać odpowiednik nazwy kwalifikowanej w starszych wersjach.
wouter bolsterlee

3
Tj Type.__module__ + '.' + Type.__qualname__.
Kentzo

4
W Pythonie 3.6 jest to tylko nazwa klasy. Nie obejmuje modułu.
jpmc26

2
@ jpmc26 W Pythonie 3.7, __qualname__nadal występuje tylko nazwa klasy
zepp.lee

22

Rozważ użycie inspectmodułu, który ma funkcje, takie jak getmoduleto, czego szukasz:

>>>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'>

7
inspect.getmodule()zwraca obiekty modułu - nie w pełni kwalifikowane nazwy klas. W rzeczywistości inspectmoduł nie zapewnia żadnej funkcjonalności, która faktycznie rozwiązałaby to pytanie. Ta odpowiedź nie jest odpowiedzią. </facepalm>
Cecil Curry,

19

Oto jedna oparta na doskonałej odpowiedzi Grega Bacona, ale z kilkoma dodatkowymi kontrolami:

__module__może być None(zgodnie z dokumentacją), a także dla typu takiego jak strmoże być __builtin__(którego możesz nie chcieć pojawiać się w logach lub czymkolwiek). Poniższe testy sprawdzają obie te możliwości:

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__

(Może być lepszy sposób sprawdzenia __builtin__. Powyższe opiera się tylko na fakcie, że str jest zawsze dostępny, a jego moduł jest zawsze __builtin__)


1
Aby zaoszczędzić innym wysiłku związanego z porównywaniem dwóch odpowiedzi: kod w odpowiedzi Grega Bacona jest teraz identyczny z kodem w tej odpowiedzi, poza tym, że Greg dodał bezcelową instrukcję else i kilka komentarzy do kodu. MB to prawdziwy bohater.
MarredCheese


9

__module__ załatwi sprawę.

Próbować:

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

Ta witryna sugeruje, że __package__może to działać w przypadku Pythona 3.0; Jednak podane tam przykłady nie będą działać na mojej konsoli Pythona 2.5.2.


6
To załatwia sprawę, dzięki! Aby uzyskać w pełni kwalifikowaną nazwę, "%s.%s" % (x.__class__.__module__, x.__class__.__name__)
użyję

7

To hack, ale obsługuję 2.6 i potrzebuję tylko czegoś prostego:

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

'logging.handlers.MemoryHandler'

1
To zależy od __repr__()implementacji w sprawdzonej klasy ( i na __str__()nie są nadpisane). W większości przypadków bezużyteczne.
z33k

7

Niektórzy (np. Https://stackoverflow.com/a/16763814/5766934 ) twierdzą, że __qualname__jest lepsze niż __name__. Oto przykład, który pokazuje różnicę:

$ 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

Uwaga, działa również poprawnie dla buildów:

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

2

Ponieważ celem tego tematu jest uzyskanie w pełni kwalifikowanych nazw, oto pułapka, która pojawia się podczas używania importu względnego wraz z głównym modułem istniejącym w tym samym pakiecie. Np. Z poniższą konfiguracją modułu:

$ 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

Oto dane wyjściowe przedstawiające wynik importowania tego samego modułu w inny sposób:

$ 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

Kiedy hum importuje pasek przy użyciu ścieżki względnej, bar widzi Baz.__module__po prostu „baz”, ale w drugim imporcie, który używa pełnej nazwy, bar widzi to samo, co „foo.baz”.

Jeśli gdzieś utrwalasz w pełni kwalifikowane nazwy, lepiej unikać importu względnego dla tych klas.


0

Żadna z odpowiedzi tutaj nie zadziałała. W moim przypadku używałem Pythona 2.7 i wiedziałem, że będę pracował tylko z objectklasami newstyle .

def get_qualified_python_name_from_class(model):
    c = model.__class__.__mro__[0]
    name = c.__module__ + "." + c.__name__
    return name
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.