Mendapatkan nama kelas dari instance?

1437

Bagaimana cara mengetahui nama kelas yang membuat instance dari objek dengan Python jika fungsi yang saya lakukan ini adalah kelas dasar dari mana kelas instance telah diturunkan?

Berpikir mungkin modul inspeksi mungkin membantu saya di sini, tetapi sepertinya tidak memberi saya apa yang saya inginkan. Dan pendek parsing __class__anggota, saya tidak yakin bagaimana mendapatkan informasi ini.

Dan
sumber
Apa sebenarnya yang Anda 'parsing' dari variabel kelas ?
sykora
1
nama tingkat atas dari kelas yang dimiliki instance (tanpa nama modul, dll ...)
Dan
Saya pikir sebaliknya akan jauh lebih sulit (untuk mendapatkan kelas di mana metode / fungsi didefinisikan).
Alexey

Jawaban:

1909

Sudahkah Anda mencoba __name__atribut kelas? yaitu type(x).__name__akan memberi Anda nama kelas, yang saya pikir adalah apa yang Anda inginkan.

>>> import itertools
>>> x = itertools.count(0)
>>> type(x).__name__
'count'

Jika Anda masih menggunakan Python 2, perhatikan bahwa metode di atas hanya berfungsi dengan kelas gaya baru (dalam Python 3+ semua kelas adalah kelas "gaya baru"). Kode Anda mungkin menggunakan beberapa kelas gaya lama. Berikut ini berfungsi untuk keduanya:

x.__class__.__name__
sykora
sumber
41
Sangat sederhana. Bertanya-tanya mengapa dir(x.__class__)tidak mencantumkannya?
cfi
43
Mengapa menggunakan __class__atas typemetode? Seperti: type(x).__name__. Bukankah memanggil anggota garis bawah dua kali secara langsung tidak disarankan? Saya tidak bisa melihat jalan keluar menggunakan __name__.
jpmc26
25
Anda harus menggunakan __class__secara langsung agar kompatibel dengan kelas gaya lama, karena tipenya hanya instance.
Quantum7
14
Ini cukup sering digunakan dalam logging, orm dan kode kerangka kerja sehingga harus benar-benar ada nama ketik bawaan (x) ... yang mengharuskan pengguna untuk melihat "nyali" untuk mendapatkan nama yang tidak terlalu pythonic, IMO.
Erik Aronesty
5
@ErikAronesty,def typename(x): return type(x).__name__
sleblanc
391

Apakah Anda ingin nama kelas sebagai string?

instance.__class__.__name__
truppo
sumber
6
Atau misalnya .__ class__ untuk mendapatkan objek kelas: D
Pencilcheck
8
Apakah aman menggunakan properti garis bawah dua kali lipat?
Eduard Luca
5
@ EduardLuca mengapa tidak aman? Properti built-in menggunakan garis bawah sehingga tidak menyebabkan konflik dengan kode yang Anda tulis
JC Rocamonde
3
Yah saya tahu bahwa garis bawah tunggal berarti / menyarankan bahwa metode / properti harus pribadi (walaupun Anda tidak dapat benar-benar menerapkan metode pribadi dalam Python AFAIK), dan saya bertanya-tanya apakah itu tidak terjadi dengan (beberapa) garis bawah ganda juga.
Eduard Luca
28
@EduardLuca menggarisbawahi pada awalnya hanya mirip dengan garis bawah tunggal di awal, tetapi bahkan lebih "pribadi" (lihat "python name mangling"). Garisbawah ganda pada awal dan akhir berbeda - yang dicadangkan untuk python dan tidak bersifat pribadi (misalnya metode ajaib seperti __init__ dan __add__).
Leagsaidh Gordon
101

Tipe() ?

>>> class A(object):
...    def whoami(self):
...       print type(self).__name__
...
>>>
>>> class B(A):
...    pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>
GHZ
sumber
ini adalah sama dengan kelas anggota, tetapi saya harus mengurai hasil ini dengan tangan, yang sedikit mengganggu ...
Dan
8
Saya suka yang ini. Dengan cara ini, dimungkinkan dalam kelas dasar untuk mendapatkan nama subclass.
joctee
6
atau self.__class__.__name__bukannya type(self).__name__mendapatkan perilaku yang sama. Kecuali ada sesuatu type()fungsi yang tidak saya sadari?
andreb
2
Jika Anda menggunakan type(item)pada item daftar, hasilnya akan <type 'instance'>sambil item.__class__.__name__memegang nama kelas.
Grochni
1
Saya pikir masalah yang menyebutkan @Grochni hanya relevan untuk kelas tertentu di Python 2.x, lihat di sini: stackoverflow.com/questions/6666856/…
Nate CK
43
class A:
  pass

a = A()
str(a.__class__)

Kode sampel di atas (ketika input dalam interpreter interaktif) akan menghasilkan '__main__.A'sebagai lawan dari 'A'yang dihasilkan jika __name__atribut dipanggil. Dengan hanya memberikan hasil A.__class__kepada strkonstruktor, parsing ditangani untuk Anda. Namun, Anda juga dapat menggunakan kode berikut jika Anda menginginkan sesuatu yang lebih eksplisit.

"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)

Perilaku ini dapat lebih disukai jika Anda memiliki kelas dengan nama yang sama yang didefinisikan dalam modul terpisah.

Kode sampel yang disediakan di atas diuji dalam Python 2.7.5.

Jonathan
sumber
Diuji dalam 2.6.6. Masih bekerja dengan baik.
Hamlett
29
type(instance).__name__ != instance.__class__.__name  #if class A is defined like
class A():
   ...

type(instance) == instance.__class__                  #if class A is defined like
class A(object):
  ...

Contoh:

>>> class aclass(object):
...   pass
...
>>> a = aclass()
>>> type(a)
<class '__main__.aclass'>
>>> a.__class__
<class '__main__.aclass'>
>>>
>>> type(a).__name__
'aclass'
>>>
>>> a.__class__.__name__
'aclass'
>>>


>>> class bclass():
...   pass
...
>>> b = bclass()
>>>
>>> type(b)
<type 'instance'>
>>> b.__class__
<class __main__.bclass at 0xb765047c>
>>> type(b).__name__
'instance'
>>>
>>> b.__class__.__name__
'bclass'
>>>
Prasath
sumber
5
Ini hanya berlaku untuk Python 2.x. Dalam 3.x, bclass () akan memutuskan untuk bclass (objek). Dan bahkan kemudian, kelas-kelas baru muncul di Python 2.2.
alcalde
16

Pertanyaan bagus.

Berikut adalah contoh sederhana berdasarkan GHZ yang mungkin membantu seseorang:

>>> class person(object):
        def init(self,name):
            self.name=name
        def info(self)
            print "My name is {0}, I am a {1}".format(self.name,self.__class__.__name__)
>>> bob = person(name='Robert')
>>> bob.info()
My name is Robert, I am a person
RyanN
sumber
13

Atau Anda dapat menggunakan classmethoddekorator:

class A:
    @classmethod
    def get_classname(cls):
        return cls.__name__

    def use_classname(self):
        return self.get_classname()

Penggunaan :

>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'
Yurii Rabeshko
sumber
10

Selain meraih __name__atribut khusus , Anda mungkin membutuhkan nama yang memenuhi syarat untuk kelas / fungsi tertentu. Ini dilakukan dengan meraih tipenya __qualname__.

Dalam kebanyakan kasus, ini akan persis sama, tetapi, ketika berhadapan dengan kelas yang bersarang / metode ini berbeda dalam output yang Anda dapatkan. Sebagai contoh:

class Spam:
    def meth(self):
        pass
    class Bar:
        pass

>>> s = Spam()
>>> type(s).__name__ 
'Spam'
>>> type(s).__qualname__
'Spam'
>>> type(s).Bar.__name__       # type not needed here
'Bar'
>>> type(s).Bar.__qualname__   # type not needed here 
'Spam.Bar'
>>> type(s).meth.__name__
'meth'
>>> type(s).meth.__qualname__
'Spam.meth'

Karena introspeksi adalah apa yang Anda cari, ini selalu ingin Anda pertimbangkan.

Dimitris Fasarakis Hilliard
sumber
2
Perlu dicatat bahwa __qualname__ini untuk Python 3.3+
FireAphis
10
Dan saya akan menghindari memberi nama pada perangkat lunak saya "meth".
Bobort
Penjelasan terkait untuk __qualname__vs __name__: stackoverflow.com/questions/58108488/what-is-qualname-in-python
ti7
0

Untuk mendapatkan instance classname:

type(instance).__name__

atau

instance.__class__.__name__

keduanya sama

v.babak
sumber