Seri bahasa pemrograman Python: #5 Fungsi

Seri bahasa pemrograman Python: #5 Fungsi

FOSS Python Fungsi Argumen Fungsi Luaran Fungsi

Fungsi adalah suatu “blok” kode yang dapat dipakai ulang untuk melakukan tugas tertentu. Dengan fungsi, program jadi lebih terstruktur, mudah di-maintenance, dan menghindari duplikasi kode.

Intuisi secara matematis \(\to\) jika pembaca mengenal notasi \(( y = f(x) )\), maka fungsi di Python juga mirip, yaitu masukan → proses → keluaran. Bedanya, fungsi Python bisa menerima banyak argumen dan mengembalikan beragam tipe data.

1) Mengapa memakai fungsi?

Beberapa alasan menggunakan fungsi dalam membuat suatu program, termasuk di Python:

  • DRY (Don’t Repeat Yourself): tulis satu kali, panggil berkali-kali.
  • Abstraksi dengan fungsi bisa mengurangi detail yang tidak perlu; fokus pada apa yang dilakukan, bukan bagaimana.
  • Pengujian dan Perbaikan yang Mudah

2) Membuat & Memanggil Fungsi

Bentuk dasar

Perhatikan kode berikut:

def nama_fungsi(parameter1, parameter2):
    # blok kode
    hasil = parameter1 + parameter2
    return hasil  # mengembalikan nilai

# pemanggilan
jumlah = nama_fungsi(2, 3)
print(jumlah)  # 5

Penjelasan:

  • def membuka definisi fungsi.
  • parameter1, parameter2 adalah parameter (variabel lokal pada fungsi, bukan variabel global).
  • return mengembalikan nilai luaran. Tanpa return, fungsi mengembalikan None alias kosong.
Fungsi tanpa nilai luaran

Meskipun tidak error, fungsi tanpa return dinilai kurang berguna, karena hal ini sama saja dengan menulis kode tanpa fungsi. Misalnya kode berikut (tanpa return), sama saja dengan mencetak teks, bukannya memberikan nilai luaran dari fungsi yang sudah didefinisikan.

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

sapa("Mohamad Zaenudin")  # mencetak teks; tidak mengembalikan nilai

3) Parameter & Argumen

a) Argumen posisi (positional) & kata kunci (keyword)

Terdapat dua cara melakukan parsing argumen, yaitu berdarakan posisi dan kata kunci. Cek kode berikut.

def luas_persegi_panjang(panjang, lebar):
    return panjang * lebar

print(luas_persegi_panjang(5, 2))              # posisi
print(luas_persegi_panjang(lebar=2, panjang=5)) # kata kunci

Memanggil kode dengan parsing argumen berdasarkan posisi maupun kata kunci sama baiknya, namun untuk keperluan yang memerlukan ketelitian, penggunaan kata kunci lebih umum digunakan.

b) Nilai default

Perhatikan kode berikut:

def pangkat(x, n=2):
    return x ** n

print(pangkat(3))     # 9 (default n=2)
print(pangkat(3, 3))  # 27

Pada kode tersebut, kita menggunakan n sebagai input fungsi, tapi sudah memberikan nilai default.

Catatan penting: JANGAN gunakan objek mutable/ (misalnya list, dict) sebagai default (lihat §10).

c) Jumlah argumen fleksibel: *args dan **kwargs

Jika kita menginginkan jumlah argumen dari fungsi yang kita buat secara fleksibel, kita bisa gunakan kode seperti contoh berikut.

def jumlahkan_semua(*args):
    total = 0
    for x in args:
        total += x
    return total

def cetak_opsi(**kwargs):
    for k, v in kwargs.items():
        print(k, "=", v)

print(jumlahkan_semua(1, 2, 3, 4))     # 10
cetak_opsi(warna="biru", ukuran=42)    # warna = biru, ukuran = 42

4) Tipe Luaran & return

Beberapa hal mengenai fungsi:

  • Kita dapat menggunakan return untuk tipe data apa pun: angka (int, float, dsb), string, list, dict, bahkan fungsi lain.
  • Bisa mengembalikan lebih dari satu nilai (namun luarannya berupa tuple). Cek kode berikut:
def statistik_sederhana(data):
    n = len(data)
    rataan = sum(data) / n
    minimum = min(data)
    maksimum = max(data)
    return rataan, minimum, maksimum  # tuple

mean, min_, max_ = statistik_sederhana([1, 2, 6, 9])

5) Dokumentasi & Anotasi Tipe

Untuk kemudahan penggunaan di masa mendatang atau berkomunikasi dengan pengembang lainnya, sebaiknya kita memberikan penjelasan dari fungsi yang kita buat. Beberapa teknik dokumentasi dan anotasi di Python.

a) Docstring

Perhatikan kode berikut yang diapit dengan tanda """.

def konversi_c_ke_f(c):
    """Konversi suhu dari Celcius ke Fahrenheit.

    Rumus:
        F = 9/5 * C + 32
    """
    return 9/5 * c + 32

print(konversi_c_ke_f.__doc__)
b) Type hints (membantu editor/linters)

Cek kode berikut ini. Sama-sama menggunakan """, namun hanya satu baris saja.

from typing import List, Tuple

def rangkum(data: List[float]) -> Tuple[float, float, float]:
    """Kembalikan nilai (mean, min, max)."""
    mean = sum(data) / len(data)
    return mean, min(data), max(data)

Catatan: Type hints tidak memaksa tipe saat runtime, tetapi sangat membantu pembacaan dan pemeriksaan secara statis.

6) Scope Variabel (LEGB) & global/nonlocal

  • LEGB: Local → Enclosing → Global → Built-in.
  • Variabel di dalam fungsi bersifat lokal, sehingga tidak bisa kita gunakan di luar scope fungsi tersebut.
x = 10  # global

def f():
    x = 5  # lokal (menutupi global di dalam fungsi)
    print(x)

f()       # 5
print(x)  # 10
Mengubah variabel global (hindari bila tidak perlu)
counter = 0

def tambah():
    global counter
    counter += 1
nonlocal (untuk nested function)
def pembuat_counter():
    hitung = 0
    def naik():
        nonlocal hitung
        hitung += 1
        return hitung
    return naik

c = pembuat_counter()
print(c(), c(), c())  # 1 2 3

7) Fungsi sebagai First-Class Citizen & Lambda

Python memperlakukan fungsi sebagai suatu objek, sehingga suatu fungsi bisa disimpan dalam variabel, dimasukkan ke list/dict, dan dikirim sebagai argumen. Perhatikan kode berikut.

def kali_dua(x): return x * 2

daftar_fungsi = [abs, kali_dua, round]
print([f(-3.7) for f in daftar_fungsi])  # [3.7, -7.4, -4]
lambda (fungsi anonim singkat)

Fungsi lambda merupakan cara singkat untuk menulis persamaan yang rumit dalam satu baris. Cek kode berikut.

kuadrat = lambda x: x * x
print(kuadrat(5))  # 25

Gunakan lambda hanya untuk fungsi yang kecil dan sederhana; untuk logika yang kompleks, lebih baik gunakan def.

8) Higher-Order Functions: map, filter, sorted, key=

Beberapa fungsi tingkat tinggi di Python.

data = [1, 2, 3, 4, 5]

# map: terapkan fungsi ke setiap elemen
kuadrat = list(map(lambda x: x*x, data))            # [1,4,9,16,25]

# filter: sisakan elemen yang memenuhi kondisi
genap = list(filter(lambda x: x % 2 == 0, data))    # [2,4]

# sorted dengan kunci
kata = ["apel", "semangka", "kiwi"]
urut = sorted(kata, key=lambda s: len(s))           # ['kiwi','apel','semangka']

9) Rekursi (Recursion)

Fungsi yang memanggil dirinya sendiri. Namun, wajib ada base case (kondisi berhenti) untuk menghindari loop tanpa batasan.

Faktorial ( n! )

Fungsi faktorial dengan rumus matematika berikut ini:

\[ n! = \begin{cases} 1, & n=0 \ n \cdot (n-1)!, & n>0 \end{cases}\]

Dapat kita tulis dengna kode Python seperti ini.

def faktorial(n):
    if n < 0:
        raise ValueError("n harus >= 0")
    if n in (0, 1):              # base case
        return 1
    return n * faktorial(n-1)    # rekursi

print(faktorial(5))  # 120

Catatan: rekursi yang berulang terlalu dalam bisa memicu RecursionError. Penggunaan iteratif kadang lebih efisien.

10) Pitfall Penting: Default Argumen Mutable

Contoh fungsi yang salah.

def tambah_item(item, daftar=[]):  # daftar dipakai ulang antar pemanggilan!
    daftar.append(item)
    return daftar

print(tambah_item(1))  # [1]
print(tambah_item(2))  # [1, 2]  (efek samping tak diinginkan)

Contoh fungsi yang benar.

def tambah_item(item, daftar=None):
    if daftar is None:
        daftar = []  # dibuat baru setiap panggilan
    daftar.append(item)
    return daftar

11) Closures & Decorators (pengantar singkat)

Closure adalah fungsi yang “mengingat” variabel dari lingkup (scope) luar tempat ia didefinisikan, bahkan setelah lingkup tersebut selesai dieksekusi. Artinya, ketika suatu fungsi didefinisikan di dalam fungsi lain, fungsi inner tersebut masih dapat mengakses variabel di fungsi luar—meskipun fungsi luar sudah tidak aktif lagi. Sementara itu, Decorator adalah fungsi yang menerima fungsi lain sebagai argumen, menambahkan atau mengubah perilakunya, lalu mengembalikan fungsi baru. Dengan kata lain, decorator adalah fungsi pembungkus (wrapper) yang memperluas fungsi lain tanpa mengubah isinya.

Closure
def pembuat_pangkat(n):
    def pangkat(x):
        return x ** n
    return pangkat

kuadrat = pembuat_pangkat(2)
kubik   = pembuat_pangkat(3)
print(kuadrat(4), kubik(4))  # 16 64
Decorator (membungkus fungsi lain)
import time

def timeit(func):
    def wrapper(*args, **kwargs):
        t0 = time.perf_counter()
        try:
            return func(*args, **kwargs)
        finally:
            dt = time.perf_counter() - t0
            print(f"{func.__name__} dieksekusi {dt:.6f} s")
    return wrapper

@timeit
def kerja_berat(n):
    return sum(i*i for i in range(n))

kerja_berat(1_000_00)  # otomatis dilaporkan durasinya

12) Penanganan Kesalahan/error di Dalam Fungsi

Kita bisa menggunakan raise untuk menolak input tak valid & try/except untuk menangkap error. Cek kode berikut

def akar(x: float) -> float:
    if x < 0:
        raise ValueError("x harus >= 0")
    return x ** 0.5

try:
    print(akar(-4))
except ValueError as e:
    print("Gagal:", e)

13) Praktik Baik (Best Practices)

  • Satu fungsi satu tugas (kohesi bernilai tinggi).
  • Nama deskriptif, mencerminkan kegunaannya hitung_rata, validasi_email.
  • Sertakan docstring & type hints.
  • Hindari efek samping yang tidak diinginkan.
  • Uji fungsi secara terpisah (unit test sederhana).

14) Mini-Proyek Ringan

Konversi Suhu
def c_to_f(c: float) -> float:
    """Celcius → Fahrenheit"""
    return 9/5 * c + 32

def f_to_c(f: float) -> float:
    """Fahrenheit → Celcius"""
    return 5/9 * (f - 32)

def c_to_k(c: float) -> float:
    """Celcius → Kelvin"""
    return c + 273.15

def k_to_c(k: float) -> float:
    """Kelvin → Celcius"""
    if k < 0:
        raise ValueError("Kelvin tidak bisa negatif")
    return k - 273.15

print(c_to_f(25), f_to_c(77), c_to_k(0), k_to_c(300))
Statistik sederhana dengan validasi
from typing import Iterable, Tuple

def stats(data: Iterable[float]) -> Tuple[float, float, float]:
    data = list(data)
    if not data:
        raise ValueError("data kosong")
    mean = sum(data) / len(data)
    return mean, min(data), max(data)

print(stats([2, 2, 4, 6, 9]))
Pembersih teks sederhana
def bersihkan_spasi(teks: str) -> str:
    return " ".join(teks.split())

def normalisasi_kalimat(teks: str) -> str:
    t = bersihkan_spasi(teks.strip())
    return t.capitalize()

print(normalisasi_kalimat("   ini    contoh   KALIMAT   "))
Pemilih motor (contoh logika keputusan)
def pilih_motor(torsi: float, kecepatan: float) -> str:
    """Sangat disederhanakan: pilih tipe motor berdasar torsi & kecepatan target."""
    if torsi > 5 and kecepatan < 200:
        return "Stepper/Servo torsi besar"
    elif torsi <= 5 and 200 <= kecepatan <= 3000:
        return "Motor DC"
    else:
        return "Motor AC / Servo (cek spesifikasi detail)"

print(pilih_motor(3.2, 1500))

15) Ringkasan

  • Gunakan fungsi untuk modularitas dan pemakaian ulang.
  • Pahami parameter (posisi, kata kunci, default, *args, **kwargs).
  • Kuasai scope (LEGB), hindari default argumen mutable.
  • Manfaatkan docstring, type hints, dan uji fungsi yang Anda buat.

Referensi:
  1. Dokumentasi Python
  2. Tutorial Python di W3School
  3. Reserved words di Python

Tambah komentar

Previous Post Next Post