Saya memiliki sesuatu yang kira-kira seperti berikut ini. Pada dasarnya saya perlu mengakses kelas metode contoh dari dekorator yang digunakan pada metode contoh dalam definisinya.
def decorator(view):
# do something that requires view's class
print view.im_class
return view
class ModelA(object):
@decorator
def a_method(self):
# do some stuff
pass
Kode apa adanya memberikan:
AttributeError: objek 'function' tidak memiliki atribut 'im_class'
Saya menemukan pertanyaan / jawaban yang serupa - Python decorator membuat fungsi lupa bahwa itu milik kelas dan Dapatkan kelas dalam dekorator Python - tetapi ini bergantung pada solusi yang mengambil contoh pada saat run-time dengan mengambil parameter pertama. Dalam kasus saya, saya akan memanggil metode berdasarkan informasi yang dikumpulkan dari kelasnya, jadi saya tidak sabar menunggu panggilan masuk.
inspect.getmro(cls)
untuk memproses semua kelas dasar di dekorator kelas untuk mendukung pewarisan.inspect
penyelamatan stackoverflow.com/a/1911287/202168Sejak python 3.6 Anda dapat menggunakan
object.__set_name__
untuk mencapai ini dengan cara yang sangat sederhana. Doc menyatakan bahwa__set_name__
"dipanggil pada saat pemilik kelas pemilik dibuat". Berikut ini contohnya:Perhatikan bahwa itu dipanggil pada waktu pembuatan kelas:
Jika Anda ingin mengetahui lebih banyak tentang bagaimana kelas dibuat dan khususnya kapan tepatnya
__set_name__
dipanggil, Anda dapat merujuk ke dokumentasi tentang "Membuat objek kelas" .sumber
@class_decorator('test', foo='bar')
def decorator(*args, **kwds): class Descriptor: ...; return Descriptor
__set_name__
meskipun saya telah menggunakan Python 3.6+ untuk waktu yang lama.hello
itu bukan metode, melainkan objek bertipeclass_decorator
.if TYPE_CHECKING
to defineclass_decorator
sebagai dekorator normal yang mengembalikan tipe yang benar.Seperti yang ditunjukkan orang lain, kelas belum dibuat pada saat dekorator dipanggil. Namun , dimungkinkan untuk membuat anotasi objek fungsi dengan parameter dekorator, lalu menghias ulang fungsi dalam metode metaclass
__new__
. Anda harus mengakses__dict__
atribut fungsi secara langsung, setidaknya bagi saya,func.foo = 1
menghasilkan AttributeError.sumber
setattr
harus digunakan daripada mengakses__dict__
Seperti yang disarankan Mark:
Kode ini menunjukkan bagaimana ini dapat bekerja menggunakan pasca-pemrosesan otomatis:
Hasil keluarannya:
Perhatikan bahwa dalam contoh ini:
Semoga ini membantu
sumber
Seperti yang ditunjukkan Semut, Anda tidak bisa mendapatkan referensi ke kelas dari dalam kelas. Namun, jika Anda tertarik untuk membedakan antara kelas yang berbeda (tidak memanipulasi objek tipe kelas yang sebenarnya), Anda dapat meneruskan string untuk setiap kelas. Anda juga dapat meneruskan parameter lain apa pun yang Anda suka ke dekorator menggunakan dekorator bergaya kelas.
Cetakan:
Juga, lihat halaman Bruce Eckel tentang dekorator.
sumber
@decorator('Bar')
sebagai lawan@Decorator('Bar')
.Apa yang dilakukan oleh flask-classy adalah membuat cache sementara yang disimpannya pada metode, kemudian menggunakan sesuatu yang lain (fakta bahwa Flask akan mendaftarkan kelas menggunakan
register
metode kelas) untuk membungkus metode tersebut.Anda dapat menggunakan kembali pola ini, kali ini menggunakan metaclass sehingga Anda dapat menggabungkan metode ini pada waktu impor.
Di kelas sebenarnya (Anda bisa melakukan hal yang sama menggunakan metaclass):
Sumber: https://github.com/apiguy/flask-classy/blob/master/flask_classy.py
sumber
Masalahnya adalah ketika dekorator dipanggil kelas tersebut belum ada. Coba ini:
Program ini akan menampilkan:
Seperti yang Anda lihat, Anda harus mencari cara lain untuk melakukan apa yang Anda inginkan.
sumber
Berikut contoh sederhananya:
Outputnya adalah:
sumber
Ini adalah pertanyaan lama tetapi muncul di Venesia. http://venusian.readthedocs.org/en/latest/
Tampaknya memiliki kemampuan untuk menghias metode dan memberi Anda akses ke kelas dan metode saat melakukannya. Perhatikan bahwa menelepon
setattr(ob, wrapped.__name__, decorated)
bukanlah cara khas menggunakan venusian dan agak mengalahkan tujuan.Either way ... contoh di bawah ini selesai dan harus dijalankan.
sumber
Fungsi tidak tahu apakah itu metode pada titik definisi, ketika kode dekorator dijalankan. Hanya ketika diakses melalui pengenal kelas / instance, ia mungkin mengetahui kelas / instansinya. Untuk mengatasi batasan ini, Anda dapat menghias dengan objek deskriptor untuk menunda kode dekorasi yang sebenarnya hingga waktu akses / panggilan:
Ini memungkinkan Anda untuk mendekorasi metode individu (statis | kelas):
Sekarang Anda dapat menggunakan kode dekorator untuk introspeksi ...
... dan untuk mengubah perilaku fungsi:
sumber
</sigh>
Seperti yang ditunjukkan oleh jawaban lain, dekorator adalah hal yang berfungsi dengan baik, Anda tidak dapat mengakses kelas tempat metode ini dimiliki karena kelas tersebut belum dibuat. Namun, tidak masalah menggunakan dekorator untuk "menandai" fungsi dan kemudian menggunakan teknik metaclass untuk menangani metode tersebut nanti, karena pada
__new__
tahap tersebut, kelas telah dibuat oleh metaclass-nya.Berikut ini contoh sederhananya:
Kami menggunakan
@field
untuk menandai metode sebagai bidang khusus dan menanganinya di metaclass.sumber
if inspect.isfunction(v) and getattr(k, "is_field", False):
seharusnya begitugetattr(v, "is_field", False)
.Anda akan memiliki akses ke kelas objek tempat metode tersebut dipanggil dalam metode dekorasi yang harus dikembalikan oleh dekorator Anda. Seperti:
Menggunakan kelas ModelA Anda, inilah yang dilakukannya:
sumber
Saya hanya ingin menambahkan contoh saya karena ia memiliki semua hal yang dapat saya pikirkan untuk mengakses kelas dari metode dekorasi. Ini menggunakan deskriptor seperti yang disarankan @tyrion. Dekorator dapat mengambil argumen dan meneruskannya ke deskriptor. Itu bisa menangani baik metode di kelas atau fungsi tanpa kelas.
sumber