Seorang dekorator mengambil fungsi, menambahkan beberapa fungsionalitas dan mengembalikannya. Dalam tutorial ini, Anda akan belajar bagaimana Anda bisa membuat dekorator dan mengapa Anda harus menggunakannya.
Dekorator dengan Python
Python memiliki fitur menarik yang disebut dekorator untuk menambahkan fungsionalitas ke kode yang sudah ada.
Ini juga disebut metaprogramming karena bagian dari program mencoba mengubah bagian lain dari program pada waktu kompilasi.
Prasyarat untuk dekorator belajar
Untuk memahami tentang dekorator, pertama-tama kita harus mengetahui beberapa hal dasar dalam Python.
Kita harus nyaman dengan fakta bahwa segala sesuatu di Python (Yes! Even class), adalah objek. Nama yang kami definisikan hanyalah pengenal yang terikat ke objek ini. Fungsi bukan pengecualian, mereka juga objek (dengan atribut). Berbagai nama berbeda dapat diikat ke objek fungsi yang sama.
Berikut ini contohnya.
def first(msg): print(msg) first("Hello") second = first second("Hello")
Keluaran
Halo Halo
Ketika Anda menjalankan kode, keduanya berfungsi first
dan second
memberikan output yang sama. Di sini, nama first
dan second
merujuk ke objek fungsi yang sama.
Sekarang hal-hal mulai menjadi lebih aneh.
Fungsi dapat diteruskan sebagai argumen ke fungsi lain.
Jika Anda pernah menggunakan fungsi like map
, filter
dan reduce
dengan Python, maka Anda sudah tahu tentang ini.
Fungsi yang mengambil fungsi lain sebagai argumen juga disebut fungsi tingkat tinggi . Berikut adalah contoh dari fungsi tersebut.
def inc(x): return x + 1 def dec(x): return x - 1 def operate(func, x): result = func(x) return result
Kami memanggil fungsi sebagai berikut.
>>> operate(inc,3) 4 >>> operate(dec,3) 2
Selanjutnya, suatu fungsi dapat mengembalikan fungsi lain.
def is_called(): def is_returned(): print("Hello") return is_returned new = is_called() # Outputs "Hello" new()
Keluaran
Halo
Di sini, is_returned()
adalah fungsi bersarang yang didefinisikan dan dikembalikan setiap kali kita memanggil is_called()
.
Terakhir, kita harus tahu tentang Closures dengan Python.
Kembali ke Dekorator
Fungsi dan metode disebut dapat dipanggil karena keduanya dapat dipanggil.
Faktanya, objek apapun yang mengimplementasikan __call__()
metode khusus disebut callable. Jadi, dalam pengertian paling dasar, dekorator adalah callable yang mengembalikan callable.
Pada dasarnya, dekorator mengambil fungsi, menambahkan beberapa fungsi, dan mengembalikannya.
def make_pretty(func): def inner(): print("I got decorated") func() return inner def ordinary(): print("I am ordinary")
Saat Anda menjalankan kode berikut di shell,
>>> ordinary() I am ordinary >>> # let's decorate this ordinary function >>> pretty = make_pretty(ordinary) >>> pretty() I got decorated I am ordinary
Pada contoh yang ditunjukkan di atas, make_pretty()
adalah dekorator. Dalam langkah penugasan:
pretty = make_pretty(ordinary)
Fungsi tersebut ordinary()
didekorasi dan fungsi yang dikembalikan diberi nama pretty
.
Kita dapat melihat bahwa fungsi dekorator menambahkan beberapa fungsi baru ke fungsi aslinya. Ini mirip dengan mengemas kado. Dekorator bertindak sebagai pembungkus. Sifat objek yang didekorasi (hadiah sebenarnya di dalam) tidak berubah. Tapi sekarang, terlihat cantik (karena didekorasi).
Umumnya, kami mendekorasi fungsi dan menetapkannya kembali sebagai,
ordinary = make_pretty(ordinary).
Ini adalah konstruksi umum dan untuk alasan ini, Python memiliki sintaks untuk menyederhanakannya.
Kita bisa menggunakan @
simbol beserta nama fungsi dekoratornya dan meletakkannya di atas definisi fungsi yang akan didekorasi. Sebagai contoh,
@make_pretty def ordinary(): print("I am ordinary")
setara dengan
def ordinary(): print("I am ordinary") ordinary = make_pretty(ordinary)
Ini hanyalah gula sintaksis untuk menerapkan dekorator.
Fungsi Dekorasi dengan Parameter
Dekorator di atas sederhana dan hanya bekerja dengan fungsi yang tidak memiliki parameter apa pun. Bagaimana jika kita memiliki fungsi yang mengambil parameter seperti:
def divide(a, b): return a/b
Fungsi ini memiliki dua parameter, a dan b. Kami tahu itu akan memberikan kesalahan jika kami mengirimkan b sebagai 0.
>>> divide(2,5) 0.4 >>> divide(2,0) Traceback (most recent call last):… ZeroDivisionError: division by zero
Sekarang mari kita buat dekorator untuk memeriksa kasus ini yang akan menyebabkan kesalahan.
def smart_divide(func): def inner(a, b): print("I am going to divide", a, "and", b) if b == 0: print("Whoops! cannot divide") return return func(a, b) return inner @smart_divide def divide(a, b): print(a/b)
Implementasi baru ini akan kembali None
jika kondisi kesalahan muncul.
>>> divide(2,5) I am going to divide 2 and 5 0.4 >>> divide(2,0) I am going to divide 2 and 0 Whoops! cannot divide
Dengan cara ini, kita dapat mendekorasi fungsi yang mengambil parameter.
Seorang pengamat yang tajam akan melihat bahwa parameter dari inner()
fungsi yang disarangkan di dalam dekorator sama dengan parameter fungsi yang didekorasi. Mempertimbangkan hal ini, sekarang kita dapat membuat dekorator umum yang bekerja dengan sejumlah parameter.
Dengan Python, keajaiban ini dilakukan sebagai function(*args, **kwargs)
. Dengan cara ini, args
akan menjadi tupel argumen posisi dan kwargs
akan menjadi kamus argumen kata kunci. Contoh dekorator seperti itu adalah:
def works_for_all(func): def inner(*args, **kwargs): print("I can decorate any function") return func(*args, **kwargs) return inner
Dekorator Rantai dengan Python
Beberapa dekorator dapat dirantai dengan Python.
Artinya, suatu fungsi dapat didekorasi beberapa kali dengan dekorator yang berbeda (atau sama). Kami cukup menempatkan dekorator di atas fungsi yang diinginkan.
def star(func): def inner(*args, **kwargs): print("*" * 30) func(*args, **kwargs) print("*" * 30) return inner def percent(func): def inner(*args, **kwargs): print("%" * 30) func(*args, **kwargs) print("%" * 30) return inner @star @percent def printer(msg): print(msg) printer("Hello")
Keluaran
****************************** %%%%%%%%%%%%%%%%%%% %%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%% ********* *********************
Sintaks di atas dari,
@star @percent def printer(msg): print(msg)
setara dengan
def printer(msg): print(msg) printer = star(percent(printer))
Urutan di mana kita rantai dekorator penting. Jika kami membalik urutannya sebagai,
@percent @star def printer(msg): print(msg)
Outputnya adalah:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************** ********** Halo ****************************** %%%%%%%% %%%%%%%%%%%%%%%%%%%%