Dapatkan nama kelas yang sepenuhnya memenuhi syarat dari suatu objek dengan Python


138

Untuk tujuan logging saya ingin mengambil nama kelas yang memenuhi syarat dari objek Python. (Dengan memenuhi syarat yang saya maksud nama kelas termasuk nama paket dan modul.)

Saya tahu tentang x.__class__.__name__, tetapi apakah ada metode sederhana untuk mendapatkan paket dan modul?

Jawaban:


150

Dengan program berikut

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

dan Bardidefinisikan sebagai

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

hasilnya adalah

$ ./prog.py
foo.Bar

2
Ini muncul untuk mengembalikan modul di mana bar didefinisikan, bukan di mana Bar didefinisikan. Jika tujuan penebangan adalah untuk mengetahui dengan tepat jenis objek itu, maka ini sepertinya tidak membantu.
Mark E. Haase

Apakah o.__class__.__module__pernah berbeda dari o.__module__?
Larsks


1
Saya sangat merekomendasikan ".".join([o.__module__, o.__name__])untuk Python3
Piotr Pęczek

Terkadang tidak bekerja:AttributeError: 'AttributeError' object has no attribute '__module__'
Hendy Irawan

39

Jawaban yang diberikan tidak berhubungan dengan kelas bertingkat. Meskipun tidak tersedia hingga Python 3.3 ( PEP 3155 ), Anda benar-benar ingin menggunakan __qualname__kelas tersebut. Pada akhirnya (3.4? PEP 395 ), __qualname__juga akan ada untuk modul untuk menangani kasus-kasus di mana modul tersebut diganti namanya (yaitu ketika namanya diubah __main__).


3
Jika Anda menggunakan github.com/wbolster/qualname Anda bisa mendapatkan qualname yang setara di versi yang lebih lama.
bolsterlee wouter

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

4
Dengan Python 3.6, ini hanya memberi saya nama kelas. Itu tidak termasuk modul.
jpmc26

3
@ jpmc26 Dengan Python 3.7, __qualname__masih hanya menyelesaikan ke nama kelas
zepp.lee

22

Pertimbangkan untuk menggunakan inspectmodul yang memiliki fungsi seperti getmoduleyang mungkin Anda cari:

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

9
inspect.getmodule()mengembalikan objek modul - nama kelas tidak sepenuhnya memenuhi syarat. Faktanya, inspectmodul tidak menyediakan fungsionalitas apa pun yang benar-benar menjawab pertanyaan ini. Jawaban ini bukan jawaban. </facepalm>
Cecil Curry

19

Ini satu berdasarkan jawaban luar biasa Greg Bacon, tetapi dengan beberapa pemeriksaan tambahan:

__module__bisa None(menurut dokumen), dan juga untuk tipe seperti stritu __builtin__(yang mungkin tidak Anda inginkan muncul di log atau apa pun). Pemeriksaan berikut untuk kedua kemungkinan tersebut:

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__

(Mungkin ada cara yang lebih baik untuk memeriksanya __builtin__. Hal di atas hanya bergantung pada fakta bahwa str selalu tersedia, dan modulnya selalu __builtin__)


4
Untuk menyelamatkan orang lain upaya membandingkan dua jawaban: kode dalam jawaban Greg Bacon sekarang identik dengan kode yang satu ini, selain itu Greg menambahkan pernyataan lain yang tidak berguna dan beberapa komentar kode. MB adalah pahlawan sejati.
MarredCheese


9

__module__ akan berhasil.

Mencoba:

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

Situs ini menyarankan bahwa __package__mungkin bekerja untuk Python 3.0; Namun, contoh yang diberikan di sana tidak akan berfungsi di bawah konsol Python 2.5.2 saya.


6
Itu berhasil, terima kasih! Untuk nama yang sepenuhnya memenuhi syarat, saya akan menggunakan "%s.%s" % (x.__class__.__module__, x.__class__.__name__)
Hanno S.

7

Ini adalah peretasan tetapi saya mendukung 2.6 dan hanya membutuhkan sesuatu yang sederhana:

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

'logging.handlers.MemoryHandler'

1
Hal ini tergantung pada __repr__()pelaksanaan di kelas diperiksa ( dan pada __str__()tidak menjadi overriden). Tidak berguna dalam banyak kasus.
z33k

7

Beberapa orang (misalnya https://stackoverflow.com/a/16763814/5766934 ) berpendapat bahwa __qualname__itu lebih baik daripada __name__. Berikut adalah contoh yang menunjukkan perbedaannya:

$ 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

Catatan, ini juga berfungsi dengan benar untuk buildin:

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

2

Karena minat dari topik ini adalah mendapatkan nama yang sepenuhnya memenuhi syarat, berikut ini adalah kesalahan yang terjadi saat menggunakan impor relatif bersama dengan modul utama yang ada dalam paket yang sama. Misalnya, dengan pengaturan modul di bawah ini:

$ 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

Berikut adalah keluaran yang menunjukkan hasil pengimporan modul yang sama secara berbeda:

$ 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

Saat impor hum bar menggunakan jalur relatif, bar Baz.__module__hanya dilihat sebagai "baz", tetapi pada import kedua yang menggunakan nama lengkap, bar terlihat sama dengan "foo.baz".

Jika Anda mempertahankan nama yang sepenuhnya memenuhi syarat di suatu tempat, lebih baik hindari impor relatif untuk kelas tersebut.


0

Tidak ada jawaban di sini yang berhasil untuk saya. Dalam kasus saya, saya menggunakan Python 2.7 dan tahu bahwa saya hanya akan bekerja dengan objectkelas gaya baru.

def get_qualified_python_name_from_class(model):
    c = model.__class__.__mro__[0]
    name = c.__module__ + "." + c.__name__
    return name
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.