Python 3.8 melengkapi bahasa dengan penanda / untuk parameter positional-only dan penanda * untuk parameter keyword-only. Keduanya mengunci cara sebuah parameter boleh diisi, sehingga antarmuka fungsi tidak berubah apabila implementasinya disunting. Topik ini membahas kedua penanda, urutan lengkap parameter, serta alasannya dipakai dalam desain fungsi.
Parameter keyword-only#
Parameter yang ditulis setelah tanda * bersifat keyword-only, yaitu wajib disebut dengan namanya dan tidak dapat diisi secara posisi. Tanda * boleh diikuti *args, atau berdiri sendiri tanpa mengumpulkan apa pun. Parameter keyword-only yang diberi nilai default menjadi opsional.
def buat_akun(nama, *, verifikasi=False):
status = "terverifikasi" if verifikasi else "menunggu"
print(nama, "-", status)
buat_akun("Ali")
buat_akun("Budi", verifikasi=True)Ali - menunggu
Budi - terverifikasiPemanggilan pertama hanya mengisi nama, sehingga verifikasi memakai defaultnya. Pemanggilan kedua menyebut verifikasi dengan namanya, dan itulah satu-satunya cara mengisinya. Pemanggilan yang mencoba mengisinya secara posisi ditolak oleh interpreter.
def buat_akun(nama, *, verifikasi=False):
status = "terverifikasi" if verifikasi else "menunggu"
print(nama, "-", status)
try:
buat_akun("Budi", True)
except TypeError as e:
print(type(e).__name__, str(e))TypeError buat_akun() takes 1 positional argument but 2 were givenPesan error menyebut jumlah argumen posisi yang diterima, bukan nama parameter yang salah, karena verifikasi memang tidak menerima posisi sama sekali. Desain semacam ini mencegah pemanggil mengirim nilai pada posisi yang urutannya mungkin berubah di masa depan.
Tanda * yang berdiri sendiri tidak menambah parameter apa pun, dan itulah bedanya dengan *args. Bentuk itu dipakai semata untuk mengunci cara pengisian parameter di belakangnya. Aturan yang sama berlaku bila fungsinya juga memuat *args, karena penanda keyword-only mengikuti kumpulan argumen posisinya.
Parameter positional-only#
Parameter yang ditulis sebelum tanda / bersifat positional-only, yaitu wajib diisi secara posisi dan ditolak apabila disebut dengan nama. Penanda / harus berada sebelum parameter apa pun yang masih boleh disebut dengan nama.
def pangkat(basis, /, eksponen=2):
return basis ** eksponen
print(pangkat(3))
print(pangkat(2, 5))
print(pangkat(3, eksponen=3))9
32
27Tiga pemanggilan di atas sah karena basis selalu diisi secara posisi, sedangkan eksponen berada di kanan / sehingga boleh diisi posisi maupun nama. Nilai defaultnya tetap bekerja seperti parameter biasa.
def pangkat(basis, /, eksponen=2):
return basis ** eksponen
try:
print(pangkat(basis=3))
except TypeError as e:
print(type(e).__name__, str(e))TypeError pangkat() got some positional-only arguments passed as keyword arguments: 'basis'Nama basis tidak diakui sebagai kata kunci karena parameternya positional-only. Nama semacam ini bebas disunting tanpa mematahkan pemanggil yang sudah ada, karena tidak ada pemanggil yang bergantung padanya.
Banyak fungsi bawaan memakai pola ini sebelum penandanya resmi ada, sehingga penanda / juga berperan menuliskan kontrak yang sebelumnya tidak tertulis. Penanda itu resmi menjadi bagian sintaks bahasa pada Python 3.8, dan sejak itu kontrak serupa dapat dinyatakan pada fungsi buatan sendiri.
Urutan lengkap parameter#
Semua bentuk parameter dapat digabung dengan urutan tetap, yaitu parameter positional-only, tanda /, parameter biasa, tanda * atau *args, parameter keyword-only, dan terakhir **kwargs. Diagram berikut merangkum urutan tersebut.
def demo(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
demo(1, 2, c=3, d=4, e=5, f=6)
demo(1, 2, 3, d=4, e=5, f=6)1 2 3 4 5 6
1 2 3 4 5 6Parameter a dan b hanya menerima posisi, c dan d menerima keduanya, sedangkan e dan f wajib disebut dengan nama. Dua pemanggilan di atas sah karena keduanya mengisi a sampai d secara posisi, lalu menyebut e dan f dengan nama. Tanda / dan * tidak muncul pada keluaran karena keduanya hanyalah penanda definisi.
Mengapa batasan cara pengisian dipakai#
Penanda ini memindahkan keputusan desain dari kebiasaan menjadi kontrak yang diperiksa interpreter. Banyak fungsi bawaan Python memakainya, misalnya len() yang parameter utamanya tidak menerima penyebutan nama, sehingga bentuk pemanggilan tertentu ditolak dengan jelas alih-alih dibiarkan. Kontrak tersebut menjelaskan parameter mana yang maknanya terikat posisi dan parameter mana yang paling terbaca bila disebut namanya.
Bagi fungsi yang dikembangkan bersama, manfaatnya terasa pada pemeliharaan. Nama parameter positional-only boleh diganti tanpa mematahkan pemanggil mana pun, karena tidak ada pemanggil yang menyebutnya. Sebaliknya, parameter penting yang rawan salah urut, seperti pilihan verifikasi=True, lebih aman dinyatakan keyword-only sehingga maksudnya terbaca pada baris pemanggilnya.
Contoh dari fungsi bawaan dapat dijalankan langsung. Fungsi len() menolak penyebutan namanya karena parameternya positional-only.
try:
print(len(obj="abc"))
except TypeError as e:
print(type(e).__name__, str(e))TypeError len() takes no keyword argumentsPola yang sama diterapkan banyak fungsi pustaka standar modern, sehingga pembaca akan menemuinya di banyak tempat. Menuliskan penanda ini pada fungsi sendiri menyatakan niat yang sama, yaitu antarmuka dirancang dengan sengaja, bukan urutan parameter yang muncul secara kebetulan.
Kesalahan umum#
Kesalahan pertama adalah mengira parameter keyword-only selalu opsional. Sifat keyword-only hanya mengatur cara pengisiannya, sedangkan kewajibannya tetap ditentukan oleh kehadiran nilai default.
def ukur(*, tinggi, berat):
return tinggi, berat
print(ukur(tinggi=170, berat=60))
try:
ukur(170, 60)
except TypeError as e:
print(type(e).__name__, str(e))(170, 60)
TypeError ukur() takes 0 positional arguments but 2 were givenTanda * sendirian tidak mengumpulkan argumen apa pun, sehingga pemanggilan dengan dua argumen posisi ditolak. Perhatikan pula bahwa kewajiban mengisi tinggi dan berat tetap berlaku meskipun keduanya tidak memiliki default.
Kesalahan kedua adalah menuliskan urutan penanda yang terbalik. Tanda / wajib mendahului tanda *, dan pelanggarannya ditolak sebagai SyntaxError sebelum program berjalan.
# tidak-dijalankan
def salah(a, *, b, /): # SyntaxError: / harus mendahului *
return a + bKesalahan ketiga adalah mengira parameter keyword-only dengan dan tanpa default tidak boleh bercampur. Pada kelompok keyword-only, parameter tanpa default boleh ditulis setelah parameter yang memiliki default, bentuk yang justru ditolak untuk parameter biasa. Fleksibilitas ini muncul karena posisi pada kelompok tersebut tidak lagi bermakna.
Ringkasan#
- Parameter setelah
*bersifat keyword-only dan wajib disebut dengan nama, sedangkan parameter sebelum/bersifat positional-only dan wajib diisi secara posisi. - Urutan lengkapnya tetap, yaitu parameter positional-only,
/, parameter biasa,*, parameter keyword-only, dan**kwargs. - Keyword-only hanya mengatur cara pengisian, sedangkan kewajiban mengisi tetap ditentukan oleh nilai default.
- Kedua penanda menjadikan aturan pemanggilan sebagai kontrak, sehingga nama dan urutan parameter pada sisi yang terkunci bebas disunting.
Referensi#
- PEP 570 – Python Positional-Only Parameters — Python Software Foundation
— Usulan resmi penanda
/beserta alasannya. - PEP 3102 – Keyword-Only Arguments — Python Software Foundation — Usulan resmi argumen keyword-only.
- More Control Flow Tools — Python Software Foundation — Bagian tutorial resmi tentang parameter khusus posisi dan kata kunci.