Learn
← Previous Next →

Hari 16: Closure, Decorator & Higher-Order Function

65 min Last updated 26 Mar 2026

Higher-Order Function

Fungsi yang menerima fungsi sebagai argumen atau mengembalikan fungsi.

def terapkan(fungsi, data):
    return [fungsi(x) for x in data]

print(terapkan(str.upper, ["halo","dunia"]))  # ['HALO','DUNIA']
print(terapkan(lambda x: x**2, [1,2,3,4]))   # [1,4,9,16]

# Fungsi sebagai nilai
operasi = {
    "tambah"  : lambda a, b: a + b,
    "kurang"  : lambda a, b: a - b,
    "kali"    : lambda a, b: a * b,
}
op = "tambah"
print(operasi[op](10, 5))  # 15

Closure

Fungsi yang "mengingat" variabel dari scope luarnya, bahkan setelah fungsi luar selesai dieksekusi.

def buat_counter(mulai=0):
    count = [mulai]          # list agar bisa dimodifikasi
    def increment(step=1):
        count[0] += step
        return count[0]
    return increment

c1 = buat_counter()
c2 = buat_counter(10)

print(c1())   # 1
print(c1())   # 2
print(c1(5))  # 7
print(c2())   # 11  — counter terpisah

def buat_pengali(faktor):
    def kali(angka):
        return angka * faktor   # faktor "ditangkap" dari luar
    return kali

kali_dua  = buat_pengali(2)
kali_lima = buat_pengali(5)
print(kali_dua(8))    # 16
print(kali_lima(8))   # 40

Decorator

Decorator membungkus fungsi dengan fungsionalitas tambahan tanpa mengubah kode aslinya.

def hitung_waktu(fungsi):
    import time
    def wrapper(*args, **kwargs):
        mulai = time.time()
        hasil = fungsi(*args, **kwargs)
        selesai = time.time()
        print(f"{fungsi.__name__} selesai dalam {selesai-mulai:.4f}s")
        return hasil
    return wrapper

@hitung_waktu
def hitung_sum(n):
    return sum(range(n))

print(hitung_sum(1_000_000))

# Decorator untuk logging
def log_call(fungsi):
    def wrapper(*args, **kwargs):
        print(f"Memanggil {fungsi.__name__}({args}, {kwargs})")
        hasil = fungsi(*args, **kwargs)
        print(f"Hasil: {hasil}")
        return hasil
    return wrapper

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

tambah(3, 5)

Decorator dengan Parameter

def ulangi(n):
    def decorator(fungsi):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                hasil = fungsi(*args, **kwargs)
            return hasil
        return wrapper
    return decorator

@ulangi(3)
def sapa(nama):
    print(f"Halo, {nama}!")

sapa("Budi")  # mencetak 3 kali

# functools.wraps — pertahankan metadata fungsi asli
from functools import wraps

def decorator_baik(fungsi):
    @wraps(fungsi)
    def wrapper(*args, **kwargs):
        return fungsi(*args, **kwargs)
    return wrapper

Assignment

Buat decorator @validasi_input yang memastikan semua argumen angka positif sebelum fungsi dijalankan. Jika ada yang negatif/nol, raise ValueError. Terapkan pada fungsi luas_persegi dan volume_kubus.

Expected output:

Luas persegi sisi 5 : 25
Volume kubus sisi 3 : 27
Error: Semua input harus positif! Dapat: -4
Error: Semua input harus positif! Dapat: 0
PY main.py
Solution
Output