Dapatkan nama kelas saat ini?

102

Bagaimana cara mendapatkan nama kelas yang saya ikuti saat ini?

Contoh:

def get_input(class_name):
    [do things]
    return class_name_result

class foo():
    input = get_input([class name goes here])

Karena sifat program yang saya antarmuka (vistrails), saya tidak dapat menggunakan __init__()untuk menginisialisasi input.

Jonathan Ginsburg
sumber

Jawaban:

158

obj.__class__.__name__ akan memberi Anda nama objek apa pun, jadi Anda dapat melakukan ini:

class Clazz():
    def getName(self):
        return self.__class__.__name__

Pemakaian:

>>> c = Clazz()
>>> c.getName()
'Clazz'
Yuval Adam
sumber
1
Mengapa ini bukan jawaban yang diterima? EDIT: Lingkup OK OP tidak dalam, itu di tingkat kelas.
KomodoDave
6
@KomodoD, karena ini salah, bahkan dalam lingkup metode. Ketika Anda memanggil getNamedari kelas anak, itu akan mengeluarkan nama kelas anak. Ini kemudian menjadi rumit jika Anda BENAR-BENAR menginginkan kelas yang Anda tangani.
Kenet Jervet
@KenetJervet Maksud Anda ketika Anda memanggil getNamedari kelas induk, itu akan menampilkan nama kelas anak? Ok ty untuk menunjukkan itu.
KomodoDave
5
Dalam istilah-OO, solusi (mengembalikan nama kelas anak waktu proses yang sebenarnya meskipun getName()metode tersebut kebetulan didefinisikan dalam superclass) sudah benar.
sxc731
22

Di dalam tubuh kelas, nama kelas belum ditentukan, sehingga tidak tersedia. Bisakah Anda tidak langsung mengetik nama kelasnya? Mungkin Anda perlu menjelaskan lebih lanjut tentang masalah tersebut agar kami dapat menemukan solusi untuk Anda.

Saya akan membuat metaclass untuk melakukan pekerjaan ini untuk Anda. Ini dipanggil pada waktu pembuatan kelas (secara konseptual di akhir kelas: blok), dan dapat memanipulasi kelas yang sedang dibuat. Saya belum menguji ini:

class InputAssigningMetaclass(type):
    def __new__(cls, name, bases, attrs):
        cls.input = get_input(name)
        return super(MyType, cls).__new__(cls, name, bases, newattrs)

class MyBaseFoo(object):
    __metaclass__ = InputAssigningMetaclass

class foo(MyBaseFoo):
    # etc, no need to create 'input'

class foo2(MyBaseFoo):
    # etc, no need to create 'input'
Ned Batchelder
sumber
UNTUK memperjelas apa yang saya coba lakukan: Saya perlu membuat dan menginisialisasi variabel kelas, 'input', di luar metode . Saya memiliki banyak kelas kecil, masing-masing harus memanggil 'get_input' menggunakan nama kelas mereka sebagai parameter. Saya mencoba untuk menggeneralisasi ini jadi saya tidak harus pergi ke setiap kelas (akan ada 100 atau lebih) dan ketik nama kelas.
Jonathan Ginsburg
Oke, saya telah memperbarui jawaban saya dengan metaclass yang akan membantu.
Ned Batchelder
1
Apa yang dimaksud MyTypedalam superbaris tersebut InputAssigningMetaclass?
A.Wan
16

Anda dapat mengaksesnya dengan atribut pribadi kelas:

cls_name = self.__class__.__name__

EDIT:

Seperti yang dikatakan Ned Batcheler, ini tidak akan berfungsi di badan kelas, tetapi akan berfungsi dalam metode.

mdeous
sumber
11

PEP 3155 diperkenalkan __qualname__, yang diimplementasikan dengan Python 3.3.

Untuk fungsi dan kelas tingkat atas, __qualname__atributnya sama dengan __name__atribut. Untuk kelas bertingkat, metode, dan fungsi bertingkat, __qualname__atribut berisi jalur titik-titik yang mengarah ke objek dari modul tingkat atas.

Ini dapat diakses dari dalam definisi kelas atau fungsi, jadi misalnya:

class Foo:
    print(__qualname__)

akan mencetak secara efektif Foo. Anda akan mendapatkan nama yang sepenuhnya memenuhi syarat (tidak termasuk nama modul), jadi Anda mungkin ingin membaginya pada .karakter.

Namun, tidak ada cara untuk mendapatkan pegangan sebenarnya pada kelas yang sedang didefinisikan.

>>> class Foo:
...     print('Foo' in globals())
... 
False
Kaki kanan
sumber
7

EDIT: Ya, Anda bisa; tetapi Anda harus menipu: Nama kelas yang sedang berjalan ada di tumpukan panggilan, dan tracebackmodul memungkinkan Anda untuk mengakses tumpukan.

>>> import traceback
>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> class foo(object):
...      _name = traceback.extract_stack()[-1][2]
...     input = get_input(_name)
... 
>>> 
>>> foo.input
'sbb'

Namun, saya tidak akan melakukan ini; Jawaban asli saya masih menjadi pilihan saya sendiri sebagai solusi. Jawaban asli:

Mungkin solusi paling sederhana adalah dengan menggunakan dekorator, yang mirip dengan jawaban Ned yang melibatkan metaclasses, tetapi kurang kuat (dekorator mampu melakukan sihir hitam, tetapi metaclasses mampu melakukan sihir hitam kuno dan okultisme )

>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> def inputize(cls):
...     cls.input = get_input(cls.__name__)
...     return cls
... 
>>> @inputize
... class foo(object):
...     pass
... 
>>> foo.input
'sbb'
>>> 
SingleNegationElimination
sumber
1
import sys

def class_meta(frame):
    class_context = '__module__' in frame.f_locals
    assert class_context, 'Frame is not a class context'

    module_name = frame.f_locals['__module__']
    class_name = frame.f_code.co_name
    return module_name, class_name

def print_class_path():
    print('%s.%s' % class_meta(sys._getframe(1)))

class MyClass(object):
    print_class_path()
Pavel Patrin
sumber
1

Saya pikir, seharusnya seperti ini:

    class foo():
        input = get_input(__qualname__)
Shtefan
sumber