BAB 22: Fungsi
Pecah program menjadi blok kode yang bisa dipanggil berulang kali — pelajari cara mendefinisikan fungsi, menerima parameter, mengembalikan nilai, dan menulis kode yang lebih terorganisir.
Di BAB 21, kita memahami bahwa variabel di Python adalah label yang menunjuk ke object di memori — bukan kotak yang menyimpan data. Pemahaman itu langsung relevan sekarang, karena ketika kamu memanggil fungsi dan melempar argumen ke dalamnya, yang berpindah bukan data itu sendiri, melainkan referensi ke object tersebut.
Tapi mari kita mundur sebentar. Selama 21 bab terakhir, semua kode yang kita tulis mengalir secara linear dari atas ke bawah — satu instruksi setelah instruksi yang lain. Pendekatan ini bekerja untuk program kecil, tapi bayangkan jika logika yang sama perlu diulang di lima tempat berbeda. Setiap kali ada perubahan, kamu harus mengubahnya di lima tempat itu sekaligus. Di sinilah fungsi mengubah cara kamu menulis kode.
Apa Itu Fungsi
Fungsi adalah blok kode yang diberi nama dan bisa dipanggil kapan saja, sebanyak yang dibutuhkan. Alih-alih mengulang instruksi yang sama berkali-kali, kamu cukup mendefinisikannya sekali lalu memanggil namanya.
Di Python, fungsi didefinisikan dengan kata kunci def:
def tampilkan_salam():
print("Selamat datang di sistem kuis!")
print("Pastikan kamu sudah menyiapkan jawaban.")
Mendefinisikan fungsi tidak langsung menjalankannya. Kode di dalam fungsi baru dieksekusi ketika fungsi dipanggil:
# kuis.py
def tampilkan_salam():
print("Selamat datang di sistem kuis!")
print("Pastikan kamu sudah menyiapkan jawaban.")
tampilkan_salam()
tampilkan_salam()
Selamat datang di sistem kuis!
Pastikan kamu sudah menyiapkan jawaban.
Selamat datang di sistem kuis!
Pastikan kamu sudah menyiapkan jawaban.
Fungsi dipanggil dua kali, dan kedua blok kode itu dieksekusi dua kali — tanpa menulis ulang isinya.
Fungsi harus didefinisikan sebelum dipanggil. Jika kamu memanggil tampilkan_salam() sebelum blok def-nya muncul di file, Python akan melempar NameError karena nama fungsi itu belum dikenal pada saat pemanggilan terjadi.
Parameter dan Argumen
Fungsi yang tidak menerima input bisa digunakan, tapi kemampuannya terbatas. Agar fungsi bisa bekerja dengan data yang berbeda-beda, kita menggunakan parameter — variabel yang dideklarasikan di dalam tanda kurung fungsi.
# kuis.py — fungsi dengan parameter
def tampilkan_skor(nama: str, skor: int):
print(f"Peserta: {nama}")
print(f"Skor: {skor}/100")
print("---")
tampilkan_skor("Rina", 87)
tampilkan_skor("Budi", 72)
tampilkan_skor("Sari", 95)
Peserta: Rina
Skor: 87/100
---
Peserta: Budi
Skor: 72/100
---
Peserta: Sari
Skor: 95/100
---
Perlu dibedakan dua istilah yang sering tertukar:
- Parameter adalah variabel yang tercantum di definisi fungsi — dalam contoh di atas,
namadanskoradalah parameter. - Argumen adalah nilai yang kamu berikan saat memanggil fungsi —
"Rina"dan87adalah argumen.
Anotasi tipe seperti nama: str dan skor: int bersifat opsional di Python, tapi sangat membantu keterbacaan. Python tidak memaksakan tipe tersebut saat runtime, tapi editor dan tools seperti mypy bisa menggunakannya untuk mendeteksi kesalahan lebih awal.
Naming Convention
Mengikuti panduan PEP 8, nama fungsi dan parameter ditulis dalam format snake_case — huruf kecil semua dengan underscore sebagai pemisah kata:
# Benar
def hitung_rata_rata(daftar_nilai: list) -> float:
pass
# Hindari
def HitungRataRata(DaftarNilai):
pass
Nilai Balik (Return Value)
Fungsi bisa mengembalikan hasil komputasinya menggunakan kata kunci return. Nilai yang dikembalikan bisa ditangkap ke variabel atau langsung digunakan dalam ekspresi.
# kuis.py — fungsi dengan return value
def hitung_nilai_akhir(skor_kuis: int, skor_tugas: int) -> float:
bobot_kuis = skor_kuis * 0.6
bobot_tugas = skor_tugas * 0.4
return bobot_kuis + bobot_tugas
nilai_rina = hitung_nilai_akhir(87, 90)
nilai_budi = hitung_nilai_akhir(72, 85)
print(f"Nilai akhir Rina: {nilai_rina:.1f}")
print(f"Nilai akhir Budi: {nilai_budi:.1f}")
Nilai akhir Rina: 88.2
Nilai akhir Budi: 77.2
Fungsi yang tidak memiliki pernyataan return secara implisit mengembalikan None. Ini bisa dibuktikan:
def cetak_pesan(pesan: str) -> None:
print(pesan)
hasil = cetak_pesan("halo")
print(hasil) # None
halo
None
Anotasi -> None pada baris definisi menandakan fungsi ini memang dirancang untuk tidak mengembalikan nilai yang bermakna.
Struktur Fungsi yang Lengkap
Sebelum melanjutkan, ada baiknya melihat ilustrasi anatomi fungsi secara visual:
Seluruh tubuh fungsi harus diindentasi lebih ke dalam dari baris def. Python menggunakan indentasi ini untuk menentukan batas tubuh fungsi — berbeda dari bahasa lain yang menggunakan kurung kurawal {}.
Kata Kunci pass
Saat merancang struktur program, kamu mungkin ingin mendefinisikan beberapa fungsi terlebih dahulu lalu mengisi implementasinya kemudian. Python membutuhkan setidaknya satu pernyataan di dalam tubuh fungsi — jika dibiarkan kosong, kode akan gagal diparse.
Kata kunci pass hadir untuk situasi ini: ia adalah pernyataan yang tidak melakukan apa-apa, tapi cukup untuk membuat sintaks Python valid.
# kuis.py — placeholder untuk fungsi yang belum diimplementasi
def ekspor_laporan(format_file: str):
pass # TODO: implementasi ekspor ke PDF dan Excel
def kirim_notifikasi(nama_peserta: str):
pass # TODO: integrasi dengan sistem email
def hitung_nilai_akhir(skor_kuis: int, skor_tugas: int) -> float:
bobot_kuis = skor_kuis * 0.6
bobot_tugas = skor_tugas * 0.4
return bobot_kuis + bobot_tugas
Dengan pass, kamu bisa menjalankan file ini sekarang — fungsi-fungsi yang belum diimplementasi tidak akan menyebabkan error selama belum dipanggil.
Fungsi dan Referensi
Ingat dari BAB 21 bahwa variabel adalah label yang menunjuk ke object? Prinsip itu berlaku juga saat melempar argumen ke fungsi. Yang berpindah ke parameter fungsi adalah referensi ke object tersebut — bukan salinan datanya.
Untuk tipe immutable seperti integer dan string, ini tidak menimbulkan masalah: perubahan di dalam fungsi tidak akan mengubah data di luar.
# kuis.py — immutable argument
def tambah_bonus(skor: int, bonus: int) -> int:
skor = skor + bonus # skor lokal menunjuk ke object baru
return skor
nilai_rina = 87
nilai_dengan_bonus = tambah_bonus(nilai_rina, 5)
print(f"nilai_rina: {nilai_rina}") # tetap 87
print(f"dengan bonus: {nilai_dengan_bonus}") # 92
nilai_rina: 87
dengan bonus: 92
Tapi untuk tipe mutable seperti list, modifikasi di dalam fungsi akan terlihat di luar:
# kuis.py — mutable argument
def tambah_peserta(daftar: list, nama: str):
daftar.append(nama) # memodifikasi object yang sama
peserta_kuis = ["Rina", "Budi"]
tambah_peserta(peserta_kuis, "Sari")
print(peserta_kuis) # ["Rina", "Budi", "Sari"]
['Rina', 'Budi', 'Sari']
Fungsi tambah_peserta tidak mengembalikan apa-apa, tapi peserta_kuis di luar fungsi tetap berubah — karena daftar di dalam fungsi dan peserta_kuis di luar keduanya menunjuk ke object list yang sama di memori.
Ini bukan bug — ini fitur yang disengaja. Tapi jika kamu ingin fungsi bekerja pada salinan tanpa mengubah original, pass salinan eksplisit: tambah_peserta(peserta_kuis[:], "Sari").
Latihan
Tiga latihan yang menggabungkan fungsi dengan konsep-konsep sebelumnya:
-
Tulis fungsi
tentukan_grade(nilai: float) -> stryang menerima nilai akhir dan mengembalikan grade berupa string ("A","B","C","D", atau"E"). Gunakan if/elif/else yang sudah dipelajari di BAB 10. Uji fungsi ini dengan beberapa nilai berbeda. -
Tulis fungsi
cetak_rekap(daftar_peserta: list)yang menerima list berisi tuple(nama, skor_kuis, skor_tugas)dan mencetak rekap nilai akhir untuk setiap peserta. Gunakan fungsihitung_nilai_akhirdari bab ini di dalam fungsi baru ini — sehingga kode tidak perlu menulis ulang logika perhitungan. -
Tulis fungsi
filter_lulus(daftar_nilai: list, batas_lulus: float) -> listyang menerima list nilai akhir dan batas kelulusan, lalu mengembalikan list baru yang hanya berisi nilai yang memenuhi syarat. Pastikan list original tidak berubah setelah fungsi dipanggil.
Fungsi adalah blok bangunan terpenting dalam program Python yang sesungguhnya. Dengan mendefinisikan fungsi, kamu mulai berpikir secara modular — memecah masalah besar menjadi bagian-bagian kecil yang masing-masing bisa ditulis, diuji, dan diperbaiki secara terpisah. Di bab selanjutnya, kita akan mendalami lebih jauh cara Python menangani argumen fungsi: bagaimana memberi nilai default, cara memanggil fungsi dengan nama parameter, dan teknik-teknik yang membuat pemanggilan fungsi jauh lebih fleksibel.