Materi Tutorial

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

Edit tutorial ini