Skip to main content

Konsep Dasar Decorators

Decorator merupakan salah satu fitur penting dalam Python yang digunakan untuk menambahkan atau meningkatkan perilaku sebuah fungsi tanpa mengubah kode asli fungsi tersebut secara langsung.

Decorator banyak digunakan dalam berbagai library dan framework Python. Untuk memahami decorator, kita terlebih dahulu perlu memahami konsep Functions as First Class Citizens.

Apa Itu Decorator?​

Decorator adalah mekanisme yang memungkinkan kita membungkus (wrap) sebuah fungsi dengan fungsi lainnya untuk memberikan perilaku tambahan.

Secara sederhana, decorator dapat dibayangkan seperti:

Fungsi asli
↓
Decorator
↓
Fungsi dengan kemampuan tambahan

Decorator pada Python biasanya digunakan dengan simbol @.

Contoh bentuk penggunaannya:

@decorator
def function():
pass

Simbol @ menunjukkan bahwa sebuah decorator diterapkan pada fungsi di bawahnya.

Decorator dapat digunakan untuk berbagai kebutuhan, misalnya:

  • Menambahkan logging.
  • Melakukan validasi.
  • Memeriksa hak akses.
  • Mengukur waktu eksekusi fungsi.
  • Menambahkan autentikasi.
  • Menambahkan perilaku tertentu tanpa mengubah fungsi asli.

Namun, sebelum mempelajari cara membuat decorator, kita perlu memahami bagaimana Python memperlakukan fungsi.

Functions as First Class Citizens​

Di Python, fungsi merupakan First Class Citizens.

Artinya, fungsi diperlakukan seperti object atau nilai biasa sehingga dapat digunakan dalam berbagai cara.

Sebuah fungsi dapat:

  • Disimpan ke dalam variabel.
  • Dikirim sebagai argument ke fungsi lain.
  • Dikembalikan dari fungsi lain.
  • Disimpan di dalam struktur data.

Kemampuan inilah yang menjadi salah satu dasar bagaimana decorator bekerja.

Menyimpan Fungsi ke Variabel​

Sebuah fungsi dapat disimpan ke dalam variabel.

Contoh:

def hello():
print("hello!")


greet = hello

greet()

Output:

hello!

Pada contoh tersebut:

greet = hello

tidak menjalankan fungsi hello().

Kita hanya memberikan referensi fungsi hello kepada variabel greet.

Karena greet sekarang mengacu pada fungsi yang sama, kita dapat menjalankannya dengan:

greet()

Menghapus Referensi Nama Fungsi​

Menariknya, kita dapat menghapus nama hello tanpa langsung menghapus fungsi tersebut.

def hello():
print("hello!")


greet = hello

del hello

greet()

Output:

hello!

Mengapa greet() masih dapat dijalankan?

Karena:

greet = hello

membuat variabel greet memiliki referensi ke object fungsi tersebut.

Ketika:

del hello

dijalankan, Python hanya menghapus nama hello sebagai referensi.

Selama masih ada referensi lain yang menunjuk ke object fungsi tersebut, fungsi tetap dapat digunakan melalui referensi tersebut.

Dalam contoh ini:

hello ──────┐
↓
Function
↑
│
greet ──────┘

Setelah:

del hello

hubungannya menjadi:

Function
↑
│
greet ──────┘

Sehingga:

greet()

tetap dapat dijalankan.

Mengoper Fungsi sebagai Argument​

Karena fungsi merupakan object, kita juga dapat mengirimkan fungsi sebagai argument ke fungsi lain.

Contoh:

def hello(func):
func()


def greet():
print("Still here!")


hello(greet)

Output:

Still here!

Perhatikan bahwa ketika mengirim fungsi sebagai argument, kita menggunakan:

hello(greet)

bukan:

hello(greet())

Perbedaannya penting.

greet

berarti kita memberikan referensi fungsi.

Sedangkan:

greet()

berarti kita menjalankan fungsi tersebut terlebih dahulu.

Dalam konteks decorator, yang dibutuhkan adalah kemampuan untuk mengirimkan referensi sebuah fungsi kepada fungsi lain.

Fungsi sebagai Return Value​

Selain dapat diberikan sebagai argument, fungsi juga dapat dikembalikan oleh fungsi lain.

Contoh:

def outer():
def inner():
print("Hello from inner function")

return inner


result = outer()

result()

Output:

Hello from inner function

Pada contoh tersebut, outer() mengembalikan fungsi inner.

return inner

Kemudian hasil tersebut disimpan:

result = outer()

Sehingga result sekarang mengacu pada fungsi inner.

Fungsi tersebut kemudian dapat dipanggil:

result()

Kemampuan fungsi untuk menerima dan mengembalikan fungsi merupakan konsep penting dalam memahami decorator.

Hubungan First Class Functions dengan Decorator​

Dari beberapa contoh sebelumnya, kita dapat melihat bahwa fungsi Python dapat:

Disimpan sebagai variabel
↓
Dikirim sebagai argument
↓
Dikembalikan sebagai return value
↓
Digunakan untuk membungkus fungsi lain
↓
Decorator

Decorator memanfaatkan kemampuan tersebut untuk memberikan perilaku tambahan kepada sebuah fungsi.

Secara konseptual:

Function
↓
dikirim sebagai argument
↓
Decorator
↓
diberikan perilaku tambahan
↓
menghasilkan function baru

Dengan demikian, decorator bukanlah konsep yang berdiri sendiri. Decorator dibangun berdasarkan kemampuan Python dalam memperlakukan fungsi sebagai First Class Citizens.

Gambaran Sederhana Decorator​

Misalnya kita memiliki fungsi:

def hello():
print("Hello")

Kita ingin menambahkan sesuatu sebelum dan sesudah fungsi tersebut dijalankan tanpa mengubah isi hello().

Secara konsep kita dapat membayangkannya:

hello()
↓
Decorator
↓
Sebelum hello()
↓
hello()
↓
Sesudah hello()

Dengan pendekatan tersebut, kode asli fungsi hello() tetap sederhana, sedangkan perilaku tambahan ditangani oleh decorator.

Kesimpulan​

Decorator merupakan fitur Python yang memungkinkan kita menambahkan atau meningkatkan perilaku sebuah fungsi tanpa mengubah implementasi asli fungsi tersebut secara langsung.

Untuk memahami decorator, konsep yang harus dipahami terlebih dahulu adalah Functions as First Class Citizens.

Fungsi di Python dapat:

  • Disimpan dalam variabel.
  • Dikirim sebagai argument.
  • Dikembalikan dari fungsi lain.
  • Digunakan sebagai bagian dari fungsi lain.

Kemampuan tersebut menjadi fondasi utama decorator.

Pada materi berikutnya, konsep ini dapat dilanjutkan dengan mempelajari Higher-Order Function, Inner Function, Closure, dan Wrapper Function sebelum masuk lebih jauh ke cara kerja decorator dengan syntax @.