Di dalam Python, fungsi adalah objek seperti nilai lain, sehingga dapat diberi nama baru, dikirim sebagai argumen, disimpan pada list atau dictionary, dan dilengkapi atribut. Sifat ini disebut fungsi sebagai objek kelas satu (first-class object). Topik ini membahas cara kerjanya beserta dua penerapannya yang paling sering muncul, yaitu fungsi sebagai argumen dan pemetaan operasi pada dictionary.
Fungsi sebagai objek#
Pernyataan def mengikat sebuah objek fungsi kepada nama. Tanda kurung melakukan pemanggilan, sedangkan nama tanpa tanda kurung menunjuk objeknya, sehingga nama baru dapat dibuat melalui penugasan biasa.
def salam():
return "Halo"
sapaan = salam
print(type(sapaan).__name__)
print(sapaan())function
HaloVariabel sapaan dan salam menunjuk objek fungsi yang sama, sehingga sapaan() menjalankan fungsi aslinya. Fungsi type() menyatakan jenisnya sebagai function, dan fungsi bawaan callable() memeriksa apakah sebuah objek dapat dipanggil. Penugasan ini tidak menyalin apa pun, melainkan menambahkan nama penunjuk yang kedua.
Karena berupa objek, fungsi dapat muncul di mana pun nilai muncul, misalnya elemen list, nilai dictionary, atau nilai kembalian fungsi lain. Sifat inilah yang dimaksud objek kelas satu, yaitu tidak ada pembatasan khusus dibandingkan nilai lainnya. Bahasa yang membatasi fungsi pada posisi tertentu tidak dapat menuliskan pola pada topik ini.
def cek_tanda(x):
return x >= 0
alias = cek_tanda
print(alias(5))
print(alias.__name__)True
cek_tandaAtribut __name__ masih menunjuk cek_tanda, yang membuktikan tidak ada fungsi kedua yang dibuat. Keduanya adalah satu objek dengan dua nama, dan pemanggilan melalui nama mana pun menghasilkan perilaku yang sama.
Fungsi sebagai argumen#
Fungsi yang menerima fungsi lain sebagai parameternya disebut fungsi tingkat tinggi (higher-order function). Pola ini memisahkan bentuk pemrosesan dari aturan yang diterapkan, sehingga satu fungsi pembantu melayani banyak aturan tanpa diubah.
def terapkan(fungsi, daftar):
return [fungsi(x) for x in daftar]
def kuadrat(x):
return x * x
def balik_kata(kata):
return kata[::-1]
print(terapkan(kuadrat, [1, 2, 3]))
print(terapkan(balik_kata, ["ali", "budi"]))[1, 4, 9]
['ila', 'idub']Fungsi terapkan tidak mengetahui isi aturannya, sedangkan kuadrat dan balik_kata menyediakan aturan masing-masing. Argumen dikirim tanpa tanda kurung, karena yang dikirim adalah objek fungsinya, bukan hasil pemanggilannya. Banyak fungsi bawaan seperti sorted() dan max() menerima parameter semacam ini melalui parameter key.
Pemisahan tersebut menurunkan duplikasi, karena bentuk pemrosesannya ditulis sekali pada terapkan dan setiap aturan ditulis sekali pada fungsinya. Menambah aturan baru berarti menambah fungsi kecil, tanpa menyentuh fungsi pembantu yang sudah teruji.
Menyimpan fungsi di dictionary#
Dictionary dapat memetakan nama operasi ke objek fungsi, sehingga pemilihan perilaku menjadi pengindeksan biasa alih-alih rangkaian if yang panjang. Bentuk ini sering disebut tabel dispatch, yaitu tabel yang meneruskan pemanggilan menurut kuncinya.
def tambah(a, b):
return a + b
def kurang(a, b):
return a - b
operasi = {"tambah": tambah, "kurang": kurang}
print(operasi["tambah"](8, 3))
print(operasi["kurang"](8, 3))11
5Pemilihan operasi berjalan dengan dua langkah, yaitu mengambil objek fungsi dari dictionary, lalu memanggilnya dengan tanda kurung. Operasi baru cukup ditambahkan sebagai entri baru, sedangkan logika pemilihnya tidak berubah sama sekali. Bentuk ini sering dipakai pada pemrosesan perintah yang masuk dari luar program.
Metode get() cocok dipakai pada tabel semacam ini, karena kunci yang tidak terdaftar dapat diarahkan ke fungsi pilihan alih-alih menimbulkan KeyError. Apabila pemanggilan tanpa kunci yang cocok memang wajar, hasil get() yang berupa None diperiksa terlebih dahulu sebelum fungsi dari tabel dipanggil.
Atribut milik fungsi#
Sebagai objek, fungsi membawa atribut bawaan yang dapat dibaca, misalnya __name__ yang menyimpan nama fungsi dan __doc__ yang menyimpan docstring. Atribut lain dapat ditambahkan melalui penugasan biasa, meskipun kebiasaan tersebut jarang diperlukan dalam program sehari-hari.
def cek_stok(jumlah):
"""Memeriksa ketersediaan stok."""
return jumlah > 0
print(cek_stok.__name__)
print(cek_stok.__doc__)cek_stok
Memeriksa ketersediaan stok.Nilai __name__ berguna pada pencatatan dan penelusuran error, karena menyebut nama fungsi yang sedang berjalan tanpa menuliskannya secara manual. Nilai __doc__ memberi akses pada dokumentasinya, dan keduanya dibaca pada saat program berjalan. Fungsi help() membaca atribut yang sama, sehingga fungsi yang sudah diberi docstring dapat diperiksa dari luar berkasnya.
Kesalahan umum#
Kesalahan pertama adalah tanda kurung yang tertinggal. Nama tanpa tanda kurung menghasilkan objek fungsinya, bukan hasil eksekusinya, sehingga nilai yang diterima variabel berupa fungsi yang belum dijalankan.
def sambutan():
return "selamat datang"
hasil = sambutan
print(callable(hasil))
print(hasil())True
selamat datangFungsi callable() mengonfirmasi bahwa hasil masih berupa fungsi, dan pemanggilannya baru menghasilkan teks. Bila objek semacam itu langsung dipakai sebagai nilai, program tampak tidak menghasilkan apa pun karena fungsinya memang belum dijalankan.
Kesalahan kedua adalah mengirim hasil pemanggilan kepada fungsi tingkat tinggi yang mengharapkan fungsi. kuadrat(3) dijalankan lebih dahulu dan menghasilkan angka 9, sehingga terapkan mencoba memanggil angka tersebut dan ditolak dengan TypeError.
def terapkan(fungsi, nilai):
return fungsi(nilai)
def kuadrat(x):
return x * x
try:
terapkan(kuadrat(3), 5)
except TypeError as e:
print(type(e).__name__, str(e))TypeError 'int' object is not callableAturan yang mudah diingat, yaitu fungsi yang menjadi argumen ditulis tanpa tanda kurung, kecuali argumen yang diharapkan memang berupa hasil. Parameter key pada sorted() mengikuti aturan pertama, sedangkan operasi matematika biasa mengikuti aturan kedua.
Kesalahan ketiga adalah mengira penugasan antar nama mengubah perilaku fungsi aslinya. Karena keduanya menunjuk objek yang sama, tidak ada salinan yang berdiri sendiri. Atribut yang dibaca dari nama alias tetap milik fungsi asli, sebagaimana ditunjukkan oleh __name__ pada bagian awal topik.
Ringkasan#
defmengikat objek fungsi kepada nama, dan nama tanpa tanda kurung menunjuk objeknya, bukan hasil pemanggilannya.- Fungsi dapat dikirim sebagai argumen kepada fungsi tingkat tinggi, dengan penulisan tanpa tanda kurung.
- Dictionary dapat memetakan nama operasi ke fungsi, sehingga pemilihan perilaku berupa pengindeksan biasa.
- Atribut
__name__dan__doc__menyimpan nama serta docstring fungsi dan dapat dibaca pada saat program berjalan.
Referensi#
- Data model — Python Software Foundation — Referensi bahasa tentang objek, nilai, dan tipe pada Python.
- Callable types — Python Software Foundation — Referensi jenis-jenis objek yang dapat dipanggil, termasuk fungsi yang didefinisikan pengguna.
- More Control Flow Tools — Python Software Foundation — Bagian tutorial resmi tentang fungsi dan pemanggilannya.