Bagaimana saya bisa mendapatkan kelas yang mendefinisikan metode dengan Python?
Saya ingin contoh berikut mencetak " __main__.FooClass
":
class FooClass:
def foo_method(self):
print "foo"
class BarClass(FooClass):
pass
bar = BarClass()
print get_class_that_defined_method(bar.foo_method)
python
python-2.6
python-datamodel
Jesse Aldridge
sumber
sumber
Jawaban:
import inspect def get_class_that_defined_method(meth): for cls in inspect.getmro(meth.im_class): if meth.__name__ in cls.__dict__: return cls return None
sumber
__dict__
! Terkadang__slots__
digunakan. Mungkin lebih baik digunakangetattr
untuk menguji apakah metode tersebut ada di kelas.Python 3
, silakan lihat jawaban ini .'function' object has no attribute 'im_class'
Terima kasih Sr2222 karena telah menunjukkan bahwa saya melewatkan intinya ...
Inilah pendekatan yang dikoreksi yang sama seperti Alex tetapi tidak perlu mengimpor apa pun. Saya tidak berpikir ini merupakan peningkatan, kecuali ada hierarki besar kelas yang diwariskan karena pendekatan ini berhenti segera setelah kelas yang menentukan ditemukan, alih-alih mengembalikan seluruh warisan seperti
getmro
halnya. Seperti yang dikatakan, ini adalah skenario yang sangat tidak mungkin.def get_class_that_defined_method(method): method_name = method.__name__ if method.__self__: classes = [method.__self__.__class__] else: #unbound method classes = [method.im_class] while classes: c = classes.pop() if method_name in c.__dict__: return c else: classes = list(c.__bases__) + classes return None
Dan Contoh:
>>> class A(object): ... def test(self): pass >>> class B(A): pass >>> class C(B): pass >>> class D(A): ... def test(self): print 1 >>> class E(D,C): pass >>> get_class_that_defined_method(A().test) <class '__main__.A'> >>> get_class_that_defined_method(A.test) <class '__main__.A'> >>> get_class_that_defined_method(B.test) <class '__main__.A'> >>> get_class_that_defined_method(C.test) <class '__main__.A'> >>> get_class_that_defined_method(D.test) <class '__main__.D'> >>> get_class_that_defined_method(E().test) <class '__main__.D'> >>> get_class_that_defined_method(E.test) <class '__main__.D'> >>> E().test() 1
Solusi Alex mengembalikan hasil yang sama. Selama pendekatan Alex dapat digunakan, saya akan menggunakannya sebagai pengganti yang ini.
sumber
Cls().meth.__self__
hanya memberi Anda contohCls
yang terikat ke contoh spesifik itumeth
. Ini analog denganCls().meth.im_class
. Jika sudahclass SCls(Cls)
, AndaSCls().meth.__self__
akan mendapatkan sebuahSCls
contoh, bukan sebuahCls
contoh. Apa yang diinginkan OP adalah mendapatkanCls
, yang tampaknya hanya tersedia dengan berjalan di MRO seperti yang dilakukan @Alex Martelli.Saya tidak tahu mengapa tidak ada yang pernah mengungkit hal ini atau mengapa jawaban teratas memiliki 50 suara positif padahal lambat sekali, tetapi Anda juga dapat melakukan hal berikut:
def get_class_that_defined_method(meth): return meth.im_class.__name__
Untuk python 3 saya yakin ini berubah dan Anda harus memeriksanya
.__qualname__
.sumber
Di Python 3, jika Anda membutuhkan objek kelas yang sebenarnya, Anda dapat melakukan:
import sys f = Foo.my_function vars(sys.modules[f.__module__])[f.__qualname__.split('.')[0]] # Gets Foo object
Jika fungsi tersebut bisa menjadi milik kelas bertingkat, Anda perlu melakukan iterasi sebagai berikut:
f = Foo.Bar.my_function vals = vars(sys.modules[f.__module__]) for attr in f.__qualname__.split('.')[:-1]: vals = vals[attr] # vals is now the class Foo.Bar
sumber
Python 3
Memecahkannya dengan cara yang sangat sederhana:
str(bar.foo_method).split(" ", 3)[-2]
Ini memberi
'FooClass.foo_method'
Pisahkan di titik untuk mendapatkan kelas dan nama fungsi secara terpisah
sumber
Saya mulai melakukan sesuatu yang agak mirip, pada dasarnya idenya adalah memeriksa setiap kali metode di kelas dasar telah diterapkan atau tidak di sub kelas. Ternyata cara saya awalnya melakukannya, saya tidak dapat mendeteksi ketika kelas menengah benar-benar menerapkan metode tersebut.
Solusi saya untuk itu sebenarnya cukup sederhana; menyetel atribut metode dan menguji keberadaannya nanti. Inilah penyederhanaan semuanya:
class A(): def method(self): pass method._orig = None # This attribute will be gone once the method is implemented def run_method(self, *args, **kwargs): if hasattr(self.method, '_orig'): raise Exception('method not implemented') self.method(*args, **kwargs) class B(A): pass class C(B): def method(self): pass class D(C): pass B().run_method() # ==> Raises Exception: method not implemented C().run_method() # OK D().run_method() # OK
UPDATE: Sebenarnya panggil
method()
darirun_method()
(bukankah itu semangatnya?) Dan minta ia meneruskan semua argumen yang tidak dimodifikasi ke metode.PS: Jawaban ini tidak langsung menjawab pertanyaan itu. IMHO ada dua alasan seseorang ingin tahu kelas mana yang mendefinisikan metode; pertama adalah mengarahkan jari ke kelas dalam kode debug (seperti dalam penanganan pengecualian), dan yang kedua adalah menentukan apakah metode tersebut telah diimplementasikan kembali (di mana metode adalah rintisan yang dimaksudkan untuk diterapkan oleh pemrogram). Jawaban ini menyelesaikan kasus kedua dengan cara yang berbeda.
sumber