Lompat ke konten Lompat ke sidebar Lompat ke footer

Memahami Decorator dalam Python

Bahasa pemrograman Python menyediakan berbagai fitur yang membantu programmer menyusun kode secara terstruktur, ringkas, dan mudah dikembangkan. Salah satu fitur yang memiliki peranan penting dalam pengembangan program adalah *decorator*. Fitur ini memungkinkan programmer menambahkan atau mengubah perilaku suatu fungsi tanpa harus mengubah secara langsung kode utama yang terdapat di dalam fungsi tersebut. Dengan memanfaatkan decorator, berbagai kebutuhan tambahan dapat diterapkan secara teratur tanpa menuliskan instruksi yang sama berulang kali pada setiap fungsi.

Sebelum mempelajari materi tentang cara Memahami Decorator dalam Python, terlebih dahulu pelajari materi tentang: Mengenal Generator dalam Python, Memahami Namespace dan Scope Variabel dalam Python, dan Memahami Python Closures.

Dalam program sederhana, sebuah fungsi biasanya dibuat untuk melaksanakan tugas tertentu, seperti menghitung nilai, mengolah data, menampilkan informasi, atau menghasilkan keluaran berdasarkan masukan. Seiring bertambahnya kompleksitas program, terkadang diperlukan proses tambahan yang berlaku pada sejumlah fungsi sekaligus. Sebagai contoh, programmer mungkin perlu menampilkan pesan sebelum dan sesudah fungsi dijalankan, memeriksa masukan, mencatat aktivitas program, atau memastikan bahwa fungsi hanya dijalankan ketika persyaratan tertentu terpenuhi.

Tanpa mekanisme yang tepat, instruksi tambahan tersebut dapat menyebabkan pengulangan kode. Setiap fungsi harus dilengkapi dengan instruksi yang serupa, sehingga program menjadi lebih panjang dan pemeliharaannya semakin sulit. Decorator memberikan pendekatan yang lebih praktis dengan membungkus fungsi menggunakan fungsi lain yang bertugas menambahkan perilaku tertentu. Fungsi utama tetap dapat menjalankan tanggung jawabnya, sedangkan perilaku tambahan dikelola secara terpisah.

Decorator berkaitan erat dengan beberapa konsep dasar Python, yaitu fungsi sebagai objek, fungsi bertingkat, fungsi yang diteruskan sebagai argumen, fungsi yang dikembalikan sebagai nilai, serta *closure*. Konsep-konsep tersebut menjadi landasan bagi mekanisme decorator. Dengan memahaminya secara bertahap, programmer dapat mengetahui bagaimana decorator bekerja dan mengapa simbol `@` dapat digunakan untuk menerapkannya dengan sintaks yang ringkas.

Pembahasan ini menguraikan pengertian decorator, prinsip kerja, penggunaan simbol `@`, penerapan pada fungsi yang memiliki parameter, penggabungan beberapa decorator, serta contoh penggunaannya dalam berbagai kebutuhan pemrograman. Setiap pembahasan dilengkapi dengan contoh kode dan hasil program agar konsep dapat dipahami secara lebih mendalam.

Pengertian Decorator dalam Python

Decorator adalah fungsi atau objek yang dapat dipanggil yang menerima suatu fungsi atau objek lain, kemudian mengembalikan fungsi atau objek dengan perilaku yang telah ditambahkan atau diubah. Dalam penggunaan yang paling umum, decorator digunakan untuk membungkus fungsi dengan fungsi lain sehingga perilaku tambahan dapat dijalankan sebelum, sesudah, atau di sekitar pelaksanaan fungsi asli.

Sebagai contoh, sebuah fungsi bernama `sapa()` bertugas menampilkan salam. Programmer dapat membuat decorator yang menampilkan pesan tambahan sebelum fungsi tersebut dijalankan. Dengan cara ini, fungsi `sapa()` tetap berisi instruksi untuk menampilkan salam, sedangkan proses tambahan ditempatkan di dalam decorator.

Perhatikan contoh berikut:
def buat_dekorasi(fungsi):
def pembungkus():
print("Program akan dijalankan")
fungsi()
return pembungkus

def sapa():
print("Halo, selamat belajar Python")

fungsi_baru = buat_dekorasi(sapa)
fungsi_baru()


Hasil program:
Program akan dijalankan
Halo, selamat belajar Python


Pada kode tersebut, `buat_dekorasi()` merupakan fungsi decorator. Fungsi tersebut menerima fungsi lain melalui parameter `fungsi`. Di dalamnya terdapat fungsi bertingkat bernama `pembungkus()` yang menampilkan pesan tambahan, kemudian menjalankan fungsi asli.

Pernyataan `return pembungkus` mengembalikan objek fungsi `pembungkus`, bukan hasil pemanggilannya. Objek fungsi tersebut kemudian disimpan dalam variabel `fungsi_baru`. Ketika `fungsi_baru()` dipanggil, pesan tambahan ditampilkan terlebih dahulu, kemudian fungsi `sapa()` dijalankan.

Contoh tersebut menunjukkan bahwa decorator dapat menambahkan perilaku baru tanpa perlu mengubah isi fungsi `sapa()`. Apabila perilaku tambahan perlu diterapkan pada fungsi lain, decorator yang sama dapat digunakan kembali selama struktur pembungkusnya sesuai dengan kebutuhan fungsi tersebut.

Konsep Dasar yang Mendukung Decorator

Sebelum mempelajari penggunaan decorator lebih lanjut, terdapat beberapa konsep Python yang perlu dipahami. Konsep-konsep tersebut menjelaskan mengapa suatu fungsi dapat menerima fungsi lain, mengembalikan fungsi, dan mempertahankan akses terhadap variabel yang berasal dari lingkungan luar.

Fungsi sebagai Objek

Dalam Python, fungsi merupakan objek. Artinya, fungsi dapat diperlakukan seperti objek lainnya. Fungsi dapat disimpan dalam variabel, diteruskan sebagai argumen, dikembalikan oleh fungsi lain, dan digunakan kembali melalui nama yang merujuk pada objek tersebut.

Perhatikan contoh berikut:
def tambah(a, b):
return a + b
operasi = tambah
print(operasi(5, 3))


Hasil program:
8

Variabel `operasi` merujuk pada objek fungsi `tambah`. Ketika `operasi(5, 3)` dipanggil, Python menjalankan fungsi yang sama dengan `tambah(5, 3)`. Hal ini menunjukkan bahwa fungsi dapat disimpan dalam variabel tanpa harus menjalankannya terlebih dahulu.

Konsep tersebut penting bagi decorator karena fungsi asli perlu diteruskan kepada decorator sebagai objek. Decorator kemudian dapat membungkus fungsi tersebut dan mengembalikan fungsi baru yang memiliki perilaku tambahan.

Fungsi sebagai Argumen

Python memungkinkan sebuah fungsi menerima fungsi lain sebagai argumen. Pendekatan ini sering digunakan ketika suatu fungsi perlu menjalankan operasi yang ditentukan oleh fungsi lain.

Contohnya adalah sebagai berikut:
def tambah(a, b):
return a + b

def hitung(operasi, x, y):
return operasi(x, y)

hasil = hitung(tambah, 4, 6)
print(hasil)


Hasil program:
10

Fungsi `hitung()` menerima tiga argumen, yaitu `operasi`, `x`, dan `y`. Argumen `operasi` diisi dengan objek fungsi `tambah`, sedangkan `x` dan `y` masing-masing bernilai `4` dan `6`. Ketika `operasi(x, y)` dijalankan, Python menjalankan fungsi `tambah(4, 6)`.

Kemampuan menerima fungsi sebagai argumen merupakan salah satu dasar pembentukan decorator. Decorator menerima fungsi yang hendak dihias, kemudian menentukan bagaimana fungsi tersebut akan dijalankan.

Mengembalikan Fungsi sebagai Nilai

Selain menerima fungsi sebagai argumen, Python memungkinkan sebuah fungsi mengembalikan fungsi lain. Kemampuan ini menjadi bagian penting dalam pembuatan decorator karena decorator umumnya mengembalikan fungsi pembungkus.

Contohnya sebagai berikut:
def buat_salam(nama):
def tampilkan():
return f"Halo, {nama}!"
return tampilkan
salam = buat_salam("Rina")
print(salam())


Hasil program:
Halo, Rina!

Fungsi `buat_salam()` mengembalikan objek fungsi `tampilkan`. Fungsi bagian dalam tersebut tetap dapat menggunakan variabel `nama` yang berasal dari fungsi luar. Hubungan ini merupakan contoh *closure*, yaitu mekanisme yang memungkinkan fungsi mempertahankan akses terhadap variabel dari lingkungan luar yang melingkupinya.

Decorator sering memanfaatkan fungsi bertingkat dan closure untuk mempertahankan akses terhadap fungsi asli serta informasi lain yang diperlukan oleh fungsi pembungkus.

Cara Kerja Decorator

Cara kerja decorator dapat dipahami melalui hubungan antara fungsi asli, fungsi decorator, dan fungsi pembungkus. Fungsi asli berisi tugas utama, decorator menerima fungsi asli sebagai argumen, sedangkan fungsi pembungkus mengatur pelaksanaan perilaku tambahan.

Perhatikan contoh berikut:
def dekorator(fungsi):
def pembungkus():
print("Sebelum fungsi dijalankan")
fungsi()
print("Sesudah fungsi dijalankan")
return pembungkus

def tampilkan_pesan():
print("Ini adalah fungsi utama")

hasil = dekorator(tampilkan_pesan)
hasil()


Hasil program:
Sebelum fungsi dijalankan
Ini adalah fungsi utama
Sesudah fungsi dijalankan


Ketika `dekorator(tampilkan_pesan)` dipanggil, objek fungsi `tampilkan_pesan` diteruskan sebagai argumen kepada decorator. Di dalam decorator, fungsi `pembungkus()` didefinisikan untuk mengatur urutan pelaksanaan instruksi.

Ketika `hasil()` dipanggil, fungsi pembungkus dijalankan. Pertama, pembungkus menampilkan pesan sebelum fungsi utama. Kedua, pembungkus memanggil fungsi asli melalui `fungsi()`. Ketiga, pembungkus menampilkan pesan setelah fungsi asli selesai dijalankan.

Urutan tersebut memperlihatkan bahwa decorator dapat mengatur proses yang berlangsung di sekitar fungsi utama. Perilaku tambahan dapat berupa pencatatan aktivitas, pemeriksaan kondisi, pengukuran waktu, atau pengolahan nilai hasil fungsi.

Perlu diperhatikan bahwa contoh di atas belum mengembalikan nilai dari fungsi asli. Jika fungsi asli menghasilkan nilai melalui `return`, fungsi pembungkus perlu mengembalikan nilai tersebut agar hasil fungsi tidak hilang. Hal ini akan dibahas pada bagian decorator dengan parameter dan nilai balik.

Penggunaan Simbol `@` pada Decorator

Python menyediakan simbol `@` sebagai sintaks ringkas untuk menerapkan decorator. Dengan sintaks ini, programmer tidak perlu secara manual memanggil decorator dan menyimpan hasilnya dalam variabel baru.

Perhatikan contoh berikut:
def dekorator(fungsi):
def pembungkus():
print("Fungsi telah dihias")
fungsi()

return pembungkus

@dekorator
def tampilkan():
print("Belajar decorator Python")
tampilkan()


Hasil program:
Fungsi telah dihias
Belajar decorator Python


Simbol `@dekorator` yang diletakkan tepat di atas definisi fungsi `tampilkan()` berarti bahwa fungsi tersebut diteruskan kepada decorator dan nama `tampilkan` kemudian merujuk pada fungsi hasil dekorasi.

Secara konseptual, kode berikut:
@dekorator
def tampilkan():
print("Belajar decorator Python")


setara dengan penerapan manual berikut:
def tampilkan():
print("Belajar decorator Python")
tampilkan = dekorator(tampilkan)


Kedua bentuk tersebut menerapkan decorator dengan tujuan yang sama. Penggunaan `@` membuat kode lebih ringkas dan memudahkan pembaca mengetahui bahwa fungsi tertentu memiliki perilaku tambahan.

Simbol `@` bukanlah operator khusus yang hanya digunakan untuk satu jenis fungsi. Dalam konteks decorator, simbol tersebut menjadi bagian dari sintaks yang menghubungkan definisi fungsi dengan decorator yang diterapkan. Nama decorator yang digunakan setelah simbol `@` harus merujuk pada objek yang dapat dipanggil dan memenuhi kebutuhan penerapan tersebut.

Decorator untuk Fungsi yang Memiliki Parameter

Decorator sederhana yang telah dibahas sebelumnya hanya dapat digunakan untuk fungsi tanpa parameter karena fungsi pembungkusnya didefinisikan tanpa argumen. Jika fungsi asli menerima parameter, pembungkus harus dirancang agar dapat menerima dan meneruskan parameter tersebut.

Sebagai contoh, sebuah fungsi pembagian membutuhkan dua argumen. Programmer dapat membuat decorator untuk memeriksa apakah penyebut bernilai nol sebelum operasi pembagian dilakukan.
def cek_pembagian(fungsi):
def pembungkus(a, b):
print("Memeriksa operasi pembagian")

if b == 0:
print("Pembagian dengan nol tidak diperbolehkan")
return None

return fungsi(a, b)
return pembungkus

@cek_pembagian
def bagi(a, b):
return a / b

print(bagi(10, 2))
print(bagi(10, 0))


Hasil program:
Memeriksa operasi pembagian
5.0
Memeriksa operasi pembagian
Pembagian dengan nol tidak diperbolehkan
None


Pada contoh tersebut, decorator `cek_pembagian()` menerima fungsi `bagi()`. Fungsi pembungkus bernama `pembungkus()` menerima dua parameter, yaitu `a` dan `b`. Sebelum fungsi asli dijalankan, pembungkus memeriksa apakah nilai `b` sama dengan nol.

Jika `b` bernilai nol, pembungkus menampilkan pesan dan mengembalikan `None`. Jika penyebut tidak nol, pembungkus menjalankan fungsi asli dengan memanggil `fungsi(a, b)` dan mengembalikan hasilnya melalui `return`.

Contoh tersebut memperlihatkan bahwa decorator dapat digunakan untuk menambahkan pemeriksaan terhadap kondisi tertentu. Namun, pembungkus yang hanya menerima dua parameter belum tentu cocok untuk semua fungsi. Jika decorator perlu digunakan pada fungsi dengan jumlah atau jenis parameter yang berbeda-beda, pendekatan yang lebih fleksibel dapat diterapkan.

Penggunaan `*args` dan `**kwargs`

Dalam Python, `*args` digunakan untuk menerima sejumlah argumen posisional, sedangkan `**kwargs` digunakan untuk menerima argumen kata kunci. Kedua fitur tersebut membantu membuat fungsi pembungkus yang dapat digunakan pada berbagai fungsi dengan susunan parameter berbeda.

Perhatikan contoh berikut:
def catat_pemanggilan(fungsi):
def pembungkus(*args, **kwargs):
print("Fungsi mulai dijalankan")

hasil = fungsi(*args, **kwargs)

print("Fungsi selesai dijalankan")
return hasil
return pembungkus

@catat_pemanggilan
def tambah(a, b):
return a + b

@catat_pemanggilan
def sapa(nama, sapaan="Halo"):
return f"{sapaan}, {nama}!"

print("Hasil:", tambah(4, 7))
print(sapa("Dina", sapaan="Selamat pagi"))


Hasil program:
Fungsi mulai dijalankan
Fungsi selesai dijalankan
Hasil: 11
Fungsi mulai dijalankan
Fungsi selesai dijalankan
Selamat pagi, Dina!


Fungsi pembungkus menggunakan `*args` dan `**kwargs` agar dapat menerima argumen posisional maupun argumen kata kunci. Argumen tersebut kemudian diteruskan kepada fungsi asli melalui `fungsi(*args, **kwargs)`.

Variabel `hasil` digunakan untuk menyimpan nilai yang dikembalikan oleh fungsi asli. Setelah pesan penutup ditampilkan, pembungkus mengembalikan nilai tersebut melalui `return hasil`. Dengan demikian, decorator tidak menghilangkan hasil yang seharusnya diterima oleh pemanggil fungsi.

Pendekatan ini lebih fleksibel dibandingkan pembungkus yang hanya menerima parameter tertentu. Meskipun demikian, `*args` dan `**kwargs` tidak otomatis menjamin semua perilaku fungsi asli tetap terjaga. Untuk membuat decorator yang lebih baik, programmer juga perlu memperhatikan informasi fungsi, seperti nama dan dokumentasinya.

Mempertahankan Informasi Fungsi dengan `functools.wraps`

Ketika decorator mengganti nama fungsi dengan fungsi pembungkus, beberapa informasi yang sebelumnya melekat pada fungsi asli dapat terlihat berubah. Sebagai contoh, atribut `__name__` pada fungsi yang telah dihias biasanya menunjukkan nama fungsi pembungkus, bukan nama fungsi asli.

Python menyediakan `functools.wraps` untuk membantu mempertahankan metadata fungsi asli pada fungsi pembungkus. Penggunaan fitur ini merupakan praktik yang dianjurkan ketika membuat decorator untuk digunakan dalam program yang lebih besar.

Perhatikan contoh berikut:
from functools import wraps

def dekorator(fungsi):
@wraps(fungsi)
def pembungkus(*args, **kwargs):
print("Menjalankan fungsi")
return fungsi(*args, **kwargs)

return pembungkus

@dekorator
def hitung_luas(panjang, lebar):
"""Menghitung luas persegi panjang."""
return panjang * lebar

print(hitung_luas(8, 5))
print(hitung_luas.__name__)
print(hitung_luas.__doc__)


Hasil program:
Menjalankan fungsi
40
hitung_luas
Menghitung luas persegi panjang.


Pada contoh tersebut, `@wraps(fungsi)` digunakan di dalam decorator untuk membantu mempertahankan metadata fungsi asli. Akibatnya, nama fungsi yang terlihat melalui `hitung_luas.__name__` tetap `hitung_luas`, sedangkan dokumentasinya tetap dapat diakses melalui `hitung_luas.__doc__`.

Metadata tersebut berguna dalam proses pemeriksaan program, pembuatan dokumentasi, pencatatan aktivitas, dan penggunaan pustaka yang memerlukan informasi mengenai fungsi. Tanpa `wraps`, fungsi pembungkus tetap dapat bekerja, tetapi informasi yang terlihat melalui sejumlah atribut fungsi dapat menjadi kurang sesuai dengan fungsi asli.

Penggunaan `functools.wraps` tidak mengubah tujuan utama decorator. Fitur ini melengkapi decorator agar perilaku tambahan dapat diterapkan tanpa kehilangan informasi penting yang melekat pada fungsi yang dibungkus.

Menggabungkan Beberapa Decorator

Python memungkinkan lebih dari satu decorator diterapkan pada sebuah fungsi. Teknik ini sering disebut *chaining decorators* atau penggabungan decorator. Setiap decorator dapat menambahkan perilaku tersendiri, sehingga satu fungsi dapat memiliki beberapa lapisan perilaku tambahan.

Perhatikan contoh berikut:
def bintang(fungsi):
def pembungkus(*args, **kwargs):
print("*" * 15)
hasil = fungsi(*args, **kwargs)
print("*" * 15)
return hasil

return pembungkus

def persen(fungsi):
def pembungkus(*args, **kwargs):
print("%" * 15)
hasil = fungsi(*args, **kwargs)
print("%" * 15)
return hasil

return pembungkus

@bintang
@persen
def tampilkan_pesan(pesan):
print(pesan)

tampilkan_pesan("Halo, Python!")


Hasil program:
***************
%%%%%%%%%%%%%%%
Halo, Python!
%%%%%%%%%%%%%%%
***************


Pada contoh tersebut, decorator `bintang` dan `persen` diterapkan pada fungsi yang sama. Decorator yang posisinya paling dekat dengan definisi fungsi, yaitu `persen`, diterapkan terlebih dahulu. Hasilnya kemudian dibungkus oleh decorator `bintang`.

Urutan penerapan tersebut secara konseptual setara dengan:
tampilkan_pesan = bintang(persen(tampilkan_pesan))

Ketika fungsi dijalankan, pembungkus `bintang` menampilkan tanda bintang terlebih dahulu. Pembungkus tersebut kemudian memanggil lapisan `persen`, yang menampilkan tanda persen sebelum menjalankan fungsi asli. Setelah fungsi asli selesai, tanda persen ditampilkan kembali, kemudian lapisan terluar menampilkan tanda bintang penutup.

Urutan decorator berpengaruh terhadap hasil akhir. Jika posisi `@bintang` dan `@persen` ditukar, susunan pesan pembuka dan penutup juga berubah. Oleh karena itu, programmer perlu memperhatikan urutan decorator ketika menggabungkan beberapa perilaku pada satu fungsi.

Decorator yang Menerima Argumen

Decorator juga dapat dirancang agar menerima argumen yang menentukan perilaku tambahan. Misalnya, programmer ingin membuat decorator yang dapat mengulang pelaksanaan suatu fungsi sebanyak jumlah tertentu. Untuk kebutuhan tersebut, diperlukan fungsi pembentuk decorator yang menerima jumlah pengulangan.

Contoh berikut menunjukkan penerapannya:
def ulangi(jumlah):
def dekorator(fungsi):
def pembungkus(*args, **kwargs):
hasil = None

for _ in range(jumlah):
hasil = fungsi(*args, **kwargs)

return hasil
return pembungkus
return dekorator

@ulangi(3)
def sapa(nama):
print("Halo,", nama)
sapa("Rina")


Hasil program:
Halo, Rina
Halo, Rina
Halo, Rina


Pada contoh tersebut, `ulangi()` merupakan fungsi pembentuk decorator. Fungsi ini menerima parameter `jumlah`, kemudian mengembalikan fungsi `dekorator`. Fungsi `dekorator` menerima fungsi asli dan mengembalikan fungsi pembungkus. Sementara itu, fungsi pembungkus menjalankan fungsi asli sebanyak nilai `jumlah`.

Ketika `@ulangi(3)` digunakan, Python terlebih dahulu memanggil `ulangi(3)` untuk menghasilkan decorator. Decorator tersebut kemudian diterapkan pada fungsi `sapa()`. Saat `sapa("Rina")` dipanggil, fungsi pembungkus menjalankan fungsi asli sebanyak tiga kali.

Contoh ini memiliki tiga tingkat fungsi, yaitu fungsi pembentuk decorator, decorator, dan fungsi pembungkus. Struktur tersebut diperlukan karena argumen `3` bukan argumen langsung untuk fungsi `sapa()`, melainkan konfigurasi yang menentukan bagaimana decorator bekerja.

Penggunaan decorator berargumen bermanfaat ketika perilaku tambahan perlu dikonfigurasi. Nilai pengulangan, tingkat pembatasan, pesan tertentu, atau parameter lain dapat diberikan saat decorator diterapkan. Dengan cara ini, satu pola decorator dapat digunakan untuk beberapa fungsi dengan konfigurasi berbeda.

Contoh Penerapan Decorator untuk Mengukur Waktu Eksekusi

Salah satu penerapan decorator yang umum adalah mengukur waktu pelaksanaan fungsi. Teknik ini membantu programmer mengetahui berapa lama suatu proses berjalan, misalnya ketika menguji efisiensi algoritma atau membandingkan dua pendekatan pengolahan data.

Contoh berikut menggunakan modul `time` untuk mengukur durasi eksekusi:
import time
from functools import wraps

def ukur_waktu(fungsi):
@wraps(fungsi)
def pembungkus(*args, **kwargs):
mulai = time.perf_counter()

hasil = fungsi(*args, **kwargs)

selesai = time.perf_counter()
durasi = selesai - mulai

print(f"Waktu eksekusi: {durasi:.6f} detik")
return hasil

return pembungkus

@ukur_waktu
def hitung_jumlah():
total = sum(range(1, 100001))
return total

print("Total:", hitung_jumlah())


Contoh keluaran:
Waktu eksekusi: 0.00xxxx detik
Total: 5000050000


Nilai durasi yang sebenarnya bergantung pada perangkat dan kondisi saat program dijalankan. Oleh karena itu, angka waktu pada keluaran dapat berbeda antara satu komputer dan komputer lainnya.

Decorator `ukur_waktu()` mencatat waktu sebelum fungsi asli dijalankan menggunakan `time.perf_counter()`. Setelah fungsi selesai, waktu kembali dicatat. Selisih kedua waktu tersebut menjadi perkiraan durasi pelaksanaan fungsi.

Fungsi pembungkus juga mengembalikan nilai hasil dari fungsi asli. Dengan demikian, fungsi `hitung_jumlah()` tetap menghasilkan jumlah bilangan yang dihitung, sementara informasi durasi ditampilkan sebagai perilaku tambahan.

Pendekatan ini dapat digunakan untuk mengukur berbagai fungsi tanpa menambahkan kode pengukuran waktu secara berulang pada setiap fungsi. Namun, pengukuran sederhana tersebut mencakup pelaksanaan fungsi beserta aktivitas yang terjadi di dalam batas pengukuran, dan hasilnya dapat dipengaruhi oleh kondisi sistem.

Contoh Penerapan Decorator untuk Validasi Masukan

Decorator dapat digunakan untuk memeriksa masukan sebelum suatu fungsi menjalankan proses utama. Validasi ini membantu memastikan bahwa data yang diterima sesuai dengan persyaratan tertentu.

Contohnya adalah fungsi yang menghitung luas persegi panjang. Panjang dan lebar tidak seharusnya bernilai negatif. 

Programmer dapat membuat decorator untuk memeriksa nilai tersebut sebelum perhitungan dilakukan:
from functools import wraps

def validasi_positif(fungsi):
@wraps(fungsi)
def pembungkus(panjang, lebar):
if panjang <= 0 or lebar <= 0:
raise ValueError(
"Panjang dan lebar harus lebih besar dari nol"
)

return fungsi(panjang, lebar)
return pembungkus

@validasi_positif
def luas_persegi_panjang(panjang, lebar):
return panjang * lebar
print(luas_persegi_panjang(8, 5))


Hasil program:
40

Decorator `validasi_positif()` memeriksa kedua parameter sebelum fungsi utama dijalankan. Jika salah satu nilai tidak memenuhi syarat, program menghasilkan `ValueError`. Jika seluruh nilai memenuhi persyaratan, fungsi asli dijalankan dan hasilnya dikembalikan.

Penggunaan `raise ValueError` membuat kesalahan masukan dinyatakan secara eksplisit. Pendekatan ini umumnya lebih tepat daripada hanya menampilkan pesan lalu melanjutkan program seolah-olah operasi berhasil.

Dalam aplikasi nyata, validasi dapat mencakup pemeriksaan jenis data, rentang angka, format teks, atau persyaratan lain. Namun, decorator validasi harus dirancang sesuai dengan tanda tangan fungsi dan aturan data yang diterapkan. Jika fungsi memiliki bentuk parameter berbeda-beda, pembungkus dapat dibuat lebih fleksibel dengan menggunakan `*args` dan `**kwargs`.

Kelebihan dan Keterbatasan Decorator

Decorator memiliki sejumlah kelebihan yang membuatnya bermanfaat dalam pengembangan program. Salah satu kelebihannya adalah mengurangi pengulangan kode. Perilaku tambahan dapat ditempatkan pada satu decorator dan diterapkan pada beberapa fungsi yang membutuhkan perilaku serupa.

Kelebihan berikutnya adalah memisahkan tanggung jawab. Fungsi utama dapat berfokus pada tugas pokoknya, sedangkan decorator menangani proses tambahan seperti pencatatan aktivitas, validasi, pengukuran waktu, atau pemeriksaan akses. Pemisahan tersebut dapat membuat struktur program lebih teratur.

Decorator juga mendukung penggunaan kembali kode. Satu decorator dapat diterapkan pada berbagai fungsi yang sesuai, sehingga programmer tidak perlu menyalin instruksi tambahan pada setiap bagian program. Selain itu, sintaks `@` membuat penerapan decorator lebih ringkas dan memudahkan pembaca mengenali perilaku tambahan yang melekat pada suatu fungsi.

Meskipun demikian, decorator memiliki keterbatasan. Penggunaan beberapa lapisan decorator dapat membuat alur pelaksanaan fungsi lebih sulit ditelusuri, terutama jika setiap lapisan mengubah argumen, hasil, atau kondisi pelaksanaan. Programmer perlu memahami urutan penerapan dan pelaksanaan decorator agar tidak terjadi kesalahan.

Decorator juga perlu dirancang dengan memperhatikan parameter dan nilai balik. Jika pembungkus tidak meneruskan argumen secara benar atau tidak mengembalikan hasil fungsi asli, perilaku fungsi dapat berubah secara tidak sengaja. Penggunaan `functools.wraps` juga penting untuk membantu mempertahankan metadata fungsi.

Oleh karena itu, decorator sebaiknya digunakan ketika perilaku tambahan memang perlu dipisahkan dan diterapkan secara konsisten. Untuk tugas yang sangat sederhana, penambahan decorator mungkin tidak diperlukan. Pemilihan teknik harus mempertimbangkan keterbacaan, kemudahan pengujian, serta kebutuhan pemeliharaan program.

Kesimpulan

Decorator merupakan fitur Python yang memungkinkan programmer menambahkan atau mengubah perilaku suatu fungsi tanpa harus mengubah secara langsung kode utama fungsi tersebut. Dalam penerapan yang umum, decorator menerima fungsi sebagai argumen, mendefinisikan fungsi pembungkus, kemudian mengembalikan fungsi pembungkus tersebut agar dapat digunakan sebagai pengganti fungsi asli.

Cara kerja decorator didukung oleh kemampuan Python memperlakukan fungsi sebagai objek. Fungsi dapat diteruskan sebagai argumen, disimpan dalam variabel, dan dikembalikan oleh fungsi lain. Fungsi bertingkat serta closure juga berperan penting karena memungkinkan pembungkus mempertahankan akses terhadap fungsi asli dan variabel yang diperlukan.

Simbol `@` menyediakan sintaks ringkas untuk menerapkan decorator. Decorator dapat digunakan pada fungsi tanpa parameter maupun fungsi yang memiliki parameter, asalkan pembungkus dirancang sesuai kebutuhan. Penggunaan `*args` dan `**kwargs` membuat pembungkus lebih fleksibel, sedangkan `functools.wraps` membantu mempertahankan informasi fungsi asli.

Selain itu, Python memungkinkan beberapa decorator diterapkan pada satu fungsi dan menyediakan pola decorator berargumen untuk mengatur perilaku tambahan. Penerapannya mencakup pencatatan aktivitas, pengukuran waktu eksekusi, validasi masukan, dan berbagai kebutuhan lain dalam pengembangan program.

Dengan memahami pengertian, prinsip kerja, dan contoh penerapannya, programmer dapat menggunakan decorator secara tepat untuk menghasilkan kode yang lebih ringkas, terstruktur, dan mudah dipelihara. Penguasaan konsep ini juga menjadi bekal penting untuk mempelajari berbagai pustaka dan kerangka kerja Python yang memanfaatkan decorator dalam pengelolaan fungsi, metode, serta perilaku program.

Artikel ini akan dibaca oleh: Firza Tegar Febrian, Gadis Lolalita, Gustaf Bintang Prayoga, Hanik Arifah, dan Haninda Cahya Ramadhani.

40 komentar untuk "Memahami Decorator dalam Python"

  1. Apa yang dimaksud dengan "green inflation"?

    BalasHapus
    Balasan
    1. Green inflation merujuk pada peningkatan biaya yang terkait dengan kebijakan atau tindakan yang bertujuan mendukung keberlanjutan dan perlindungan lingkungan.

      Hapus
  2. Apa yang menjadi penyebab utama green inflation?

    BalasHapus
    Balasan
    1. Faktor penyebab green inflation melibatkan investasi dalam teknologi hijau, perubahan kebijakan yang mendukung lingkungan, dan upaya untuk mengurangi dampak ekologis.

      Hapus
  3. Bagaimana teknologi hijau dapat berkontribusi terhadap green inflation?

    BalasHapus
    Balasan
    1. Penerapan teknologi hijau seringkali memerlukan investasi awal yang tinggi, sehingga dapat menaikkan biaya produksi atau layanan.

      Hapus
  4. Apa peran kebijakan dalam green inflation?

    BalasHapus
    Balasan
    1. Kebijakan pro lingkungan, seperti pajak karbon atau insentif untuk energi terbarukan, dapat menciptakan green inflation dengan mengubah dinamika biaya dalam perekonomian.

      Hapus
  5. Bagaimana green inflation dapat memengaruhi sektor ekonomi tertentu?

    BalasHapus
    Balasan
    1. Green inflation dapat memberikan tekanan tambahan pada sektor-sektor ekonomi tertentu, terutama yang sangat tergantung pada sumber daya energi atau praktik konvensional.

      Hapus
  6. Apa dampak green inflation terhadap konsumen?

    BalasHapus
    Balasan
    1. Green inflation dapat menyebabkan kenaikan harga barang dan layanan, memberikan dampak langsung pada konsumen dengan meningkatkan biaya hidup.

      Hapus
  7. Bagaimana perubahan perilaku konsumen dapat mempengaruhi green inflation?

    BalasHapus
    Balasan
    1. Jika konsumen lebih memilih produk dan layanan ramah lingkungan, ini dapat mendorong lebih banyak perusahaan untuk mengadopsi praktik hijau, tetapi juga dapat meningkatkan permintaan dan harga.

      Hapus
  8. Apa peran pendidikan masyarakat dalam mengatasi green inflation?

    BalasHapus
    Balasan
    1. Pendidikan masyarakat dapat meningkatkan kesadaran tentang pentingnya praktik-praktik ramah lingkungan, sehingga masyarakat lebih siap mendukung perubahan tersebut.

      Hapus
  9. Mengapa kebijakan pro-lingkungan dapat menyebabkan ketidaksetaraan sosial?

    BalasHapus
    Balasan
    1. Peningkatan biaya untuk industri tertentu dapat menciptakan ketidaksetaraan ekonomi, terutama jika tidak ada langkah-langkah untuk melibatkan atau melindungi kelompok masyarakat dengan pendapatan rendah.

      Hapus
  10. Bagaimana pemerintah dapat merancang kebijakan yang seimbang untuk mengatasi green inflation?

    BalasHapus
    Balasan
    1. Pemerintah perlu mempertimbangkan dampak ekonomi dan sosial dari kebijakan pro-lingkungan, mencari keseimbangan antara perlindungan lingkungan dan stabilitas ekonomi.

      Hapus
  11. Apa dampak green inflation terhadap investasi dalam inovasi teknologi hijau?

    BalasHapus
    Balasan
    1. Green inflation dapat mendorong investasi dalam inovasi teknologi hijau, tetapi juga dapat menimbulkan tantangan finansial bagi perusahaan untuk mengadopsi teknologi tersebut.

      Hapus
  12. Bagaimana perubahan iklim dapat mempengaruhi green inflation?

    BalasHapus
    Balasan
    1. Perubahan iklim dapat meningkatkan urgensi untuk mengadopsi praktik-praktik ramah lingkungan, tetapi juga dapat menciptakan tekanan finansial tambahan untuk mengatasi dampak perubahan iklim.

      Hapus
  13. Mengapa transparansi dalam kebijakan lingkungan penting untuk mengurangi ketidakpastian ekonomi?

    BalasHapus
    Balasan
    1. Transparansi dapat membantu pelaku ekonomi memahami dampak kebijakan lingkungan, mengurangi ketidakpastian, dan memberikan kejelasan mengenai arah ekonomi.

      Hapus
  14. Bagaimana pelaku bisnis dapat beradaptasi dengan green inflation?

    BalasHapus
    Balasan
    1. Bisnis dapat beradaptasi dengan green inflation dengan mengadopsi praktik-praktik ramah lingkungan, meningkatkan efisiensi operasional, dan berinovasi untuk mengurangi dampak lingkungan.

      Hapus
  15. Apa peran lembaga keuangan dalam mendukung proyek-proyek yang berkelanjutan?

    BalasHapus
    Balasan
    1. Lembaga keuangan dapat mendukung proyek-proyek yang berkelanjutan melalui pemberian pinjaman atau investasi pada inisiatif yang mendukung tujuan keberlanjutan.

      Hapus
  16. Mengapa perlu adanya kerja sama internasional dalam mengatasi green inflation?

    BalasHapus
    Balasan
    1. Isu lingkungan melibatkan batas negara, dan kerja sama internasional diperlukan untuk mengatasi tantangan keberlanjutan secara global.

      Hapus
  17. Bagaimana pendekatan sektor swasta dapat membantu mengatasi green inflation?

    BalasHapus
    Balasan
    1. Sektoral swasta dapat berperan dengan mengadopsi praktik-praktik bisnis yang berkelanjutan, berinvestasi dalam inovasi hijau, dan berpartisipasi dalam kemitraan untuk mendukung keberlanjutan.

      Hapus
  18. Mengapa penting bagi perusahaan untuk melibatkan pemangku kepentingan dalam kebijakan hijau mereka?

    BalasHapus
    Balasan
    1. Melibatkan pemangku kepentingan membantu menciptakan dukungan untuk kebijakan hijau, mengurangi resistensi, dan membangun reputasi positif di mata konsumen dan masyarakat.

      Hapus
  19. Apa dampak peningkatan permintaan akan produk hijau terhadap harga?

    BalasHapus
    Balasan
    1. Peningkatan permintaan dapat mendorong kenaikan harga produk hijau, memberikan insentif bagi lebih banyak perusahaan untuk beralih ke praktik-praktik yang ramah lingkungan.

      Hapus
  20. Bagaimana masyarakat dapat berkontribusi dalam mengatasi green inflation?

    BalasHapus
    Balasan
    1. Masyarakat dapat berkontribusi dengan meningkatkan kesadaran, mendukung produk dan layanan hijau, serta mengambil tindakan kecil dalam kehidupan sehari-hari untuk mengurangi dampak lingkungan.

      Hapus

Hubungi admin melalui Wa : +62-896-2414-6106

Respon komentar 7 x 24 jam, mohon bersabar jika komentar tidak langsung dipublikasi atau mendapatkan balasan secara langsung.

Bantu admin meningkatkan kualitas blog dengan melaporkan berbagai permasalahan seperti typo, link bermasalah, dan lain sebagainya melalui kolom komentar.

- Ikatlah Ilmu dengan Memostingkannya -