Dalam Python 2.5, apakah ada cara untuk membuat dekorator yang menghiasi kelas? Secara khusus, saya ingin menggunakan dekorator untuk menambahkan anggota ke kelas dan mengubah konstruktor untuk mengambil nilai bagi anggota itu.
Mencari sesuatu seperti berikut (yang memiliki kesalahan sintaks pada 'class Foo:':
def getId(self): return self.__id
class addID(original_class):
def __init__(self, id, *args, **kws):
self.__id = id
self.getId = getId
original_class.__init__(self, *args, **kws)
@addID
class Foo:
def __init__(self, value1):
self.value1 = value1
if __name__ == '__main__':
foo1 = Foo(5,1)
print foo1.value1, foo1.getId()
foo2 = Foo(15,2)
print foo2.value1, foo2.getId()
Saya kira apa yang benar-benar saya cari adalah cara untuk melakukan sesuatu seperti antarmuka C # dengan Python. Saya perlu mengubah paradigma saya, saya kira.
sumber
Terlepas dari pertanyaan apakah dekorator kelas adalah solusi tepat untuk masalah Anda:
Dalam Python 2.6 dan lebih tinggi, ada dekorator kelas dengan @ -syntax, sehingga Anda dapat menulis:
Dalam versi yang lebih lama, Anda dapat melakukannya dengan cara lain:
Namun perlu dicatat bahwa ini berfungsi sama seperti untuk dekorator fungsi, dan bahwa dekorator harus mengembalikan kelas baru (atau modifikasi asli), yang bukan apa yang Anda lakukan dalam contoh. Dekorator addID akan terlihat seperti ini:
Anda kemudian dapat menggunakan sintaks yang sesuai untuk versi Python Anda seperti dijelaskan di atas.
Tetapi saya setuju dengan orang lain bahwa warisan lebih cocok jika Anda ingin menimpanya
__init__
.sumber
Tidak ada yang menjelaskan bahwa Anda dapat mendefinisikan kelas secara dinamis. Jadi, Anda dapat memiliki dekorator yang mendefinisikan (dan mengembalikan) subkelas:
Yang dapat digunakan dalam Python 2 (komentar dari Blckknght yang menjelaskan mengapa Anda harus terus melakukan ini dalam 2.6+) seperti ini:
Dan dengan Python 3 seperti ini (tapi hati-hati menggunakannya
super()
di kelas Anda):Jadi Anda dapat memiliki kue dan memakannya - warisan dan dekorator!
sumber
super
panggilan di kelas aslinya. JikaFoo
ada metode bernamafoo
yang memanggilnyasuper(Foo, self).foo()
akan berulang tanpa batas, karena namaFoo
terikat ke subclass yang dikembalikan oleh dekorator, bukan kelas asli (yang tidak dapat diakses dengan nama apa pun). Argumen Python 3super()
menghindari masalah ini (saya berasumsi melalui sihir kompiler yang sama yang memungkinkannya bekerja sama sekali). Anda juga dapat mengatasi masalah dengan mendekorasi kelas secara manual dengan nama yang berbeda (seperti yang Anda lakukan pada contoh Python 2.5).Itu bukan praktik yang baik dan tidak ada mekanisme untuk melakukan itu karena itu. Cara yang tepat untuk mencapai apa yang Anda inginkan adalah warisan.
Lihatlah dokumentasi kelas .
Sedikit contoh:
Dengan cara ini Boss memiliki segalanya
Employee
, dengan__init__
metode dan anggota sendiri.sumber
Saya setuju warisan lebih cocok untuk masalah yang diajukan.
Saya menemukan pertanyaan ini sangat berguna pada kelas dekorasi, terima kasih semua.
Berikut adalah beberapa contoh lain, berdasarkan jawaban lain, termasuk bagaimana pewarisan mempengaruhi hal-hal di Python 2.7, (dan @wraps , yang memelihara dokumentasi fungsi asli, dll.):
Seringkali Anda ingin menambahkan parameter ke dekorator Anda:
Output:
Saya telah menggunakan fungsi dekorator, karena saya menemukan mereka lebih ringkas. Berikut kelas untuk mendekorasi kelas:
Versi yang lebih kuat yang memeriksa tanda kurung itu, dan berfungsi jika metode tidak ada pada kelas yang didekorasi:
The
assert
cek yang dekorator belum digunakan tanpa tanda kurung. Jika sudah, maka kelas yang sedang didekorasi dilewatkan kemsg
parameter dekorator, yang menimbulkanAssertionError
.@decorate_if
hanya berlakudecorator
jikacondition
dievaluasiTrue
.The
getattr
,callable
tes, dan@decorate_if
digunakan sehingga dekorator tidak pecah jikafoo()
metode tidak ada pada kelas yang dihiasi.sumber
Sebenarnya ada penerapan dekorator kelas yang cukup baik di sini:
https://github.com/agiliq/Django-parsley/blob/master/parsley/decorators.py
Sebenarnya saya pikir ini adalah implementasi yang cukup menarik. Karena subclass kelas yang didekorasi, ia akan berperilaku persis seperti kelas ini dalam hal-hal seperti
isinstance
cek.Ini memiliki manfaat tambahan: itu tidak biasa untuk
__init__
pernyataan dalam Formulir django kustom untuk membuat modifikasi atau penambahanself.fields
sehingga lebih baik untuk perubahanself.fields
terjadi setelah semua__init__
telah berjalan untuk kelas yang bersangkutan.Sangat pintar.
Namun, di kelas Anda, Anda benar-benar ingin dekorasi mengubah konstruktor, yang menurut saya bukan kasus yang baik untuk dekorator kelas.
sumber
Berikut adalah contoh yang menjawab pertanyaan mengembalikan parameter kelas. Selain itu, masih menghormati rantai warisan, yaitu hanya parameter kelas itu sendiri yang dikembalikan. Fungsi
get_params
ditambahkan sebagai contoh sederhana, tetapi fungsi lain dapat ditambahkan berkat modul inspeksi.sumber
Django memiliki
method_decorator
dekorator yang mengubah dekorator apa pun menjadi dekorator metode, Anda dapat melihat bagaimana penerapannya didjango.utils.decorators
:https://github.com/django/django/blob/50cf183d219face91822c75fa0a15fe2fe3cb32d/django/utils/decorators.py#L53
https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/#decorating-the-class
sumber