Decorators & Closures Python
Decorators dan Closures adalah dua konsep tingkat lanjut di Python yang sangat powerful. Meskipun terdengar mengintimidasi, keduanya adalah fondasi dari banyak "sihir" yang terjadi di dalam framework populer seperti Django, Flask, dan FastAPI.
Bayangkan Anda memiliki sebuah kado (fungsi). Anda ingin membungkus kado tersebut dengan kertas kado yang indah (decorator) sebelum memberikannya kepada orang lain. Anda tidak mengubah isi kadonya, tetapi Anda "mempercantik" atau menambah fitur pada kado tersebut dari luar. Itulah inti dari Decorator: memodifikasi perilaku fungsi tanpa mengubah kode aslinya.
Sebelum masuk ke Decorator, kita perlu memahami konsep Closures terlebih dahulu.
1. Closures
Closure adalah fungsi yang "mengingat" variabel dari lingkup (scope) tempat ia dibuat, bahkan setelah lingkup tersebut selesai dieksekusi.
Konsep Nested Function
Di Python, kita bisa membuat fungsi di dalam fungsi:
def luar(x):
def dalam(y):
return x + y
return dalam
Membuat Closure
Perhatikan contoh ini:
def pembuat_pengali(n):
def pengali(x):
return x * n
return pengali
# Membuat closure
kali_tiga = pembuat_pengali(3)
kali_lima = pembuat_pengali(5)
print(kali_tiga(10)) # Output: 30
print(kali_lima(10)) # Output: 50
Di sini, fungsi kali_tiga masih "mengingat" bahwa nilai n adalah 3, meskipun fungsi pembuat_pengali sudah selesai dijalankan. Inilah Closure.
2. Decorators
Decorator pada dasarnya adalah Closure yang menerima fungsi sebagai argumen dan mengembalikan fungsi pengganti (wrapper).
Decorator Sederhana
def decorator_saya(func):
def wrapper():
print("Sebelum fungsi dipanggil")
func()
print("Setelah fungsi dipanggil")
return wrapper
@decorator_saya
def say_hello():
print("Hello World!")
say_hello()
Output:
Sebelum fungsi dipanggil
Hello World!
Setelah fungsi dipanggil
3. Decorator dengan Argumen (*args, **kwargs)
Agar decorator bisa bekerja dengan fungsi apa pun (yang memiliki parameter berapapun), gunakan *args dan **kwargs.
def log_fungsi(func):
def wrapper(*args, **kwargs):
print(f"Panggilan fungsi: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_fungsi
def tambah(a, b):
return a + b
print(tambah(3, 5))
# Output:
# Panggilan fungsi: tambah
# 8
4. Real World Examples
Timer Decorator (Mengukur Waktu Eksekusi)
Sangat berguna untuk optimasi performa.
import time
from functools import wraps
def timer(func):
@wraps(func) # Praktik terbaik: menjaga metadata fungsi asli
def wrapper(*args, **kwargs):
start = time.time()
hasil = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} berjalan selama {end - start:.4f} detik")
return hasil
return wrapper
@timer
def proses_berat():
time.sleep(1)
return "Selesai"
proses_berat()
Authentication Decorator (Contoh Flask)
Memastikan user sudah login sebelum mengakses halaman tertentu.
def login_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not current_user.is_authenticated:
return redirect('/login')
return func(*args, **kwargs)
return wrapper
@app.route('/dashboard')
@login_required
def dashboard():
return "Halaman Dashboard"
Kesimpulan
- Closure: Fungsi yang mengingat state dari lingkup luarnya.
- Decorator: Cara elegan menggunakan Closure untuk memodifikasi fungsi.