Sebagian fungsi tidak menetapkan jumlah parameternya di muka, misalnya fungsi penjumlahan yang menerima sejumlah angka atau pembungkus yang meneruskan argumen ke fungsi lain. Python menyediakan parameter *args dan **kwargs untuk kebutuhan tersebut. Topik ini membahas keduanya, penggabungannya dengan parameter biasa, serta pola penerusan argumen yang menjadi dasar wrapper dan decorator.
Menerima sejumlah argumen dengan *args#
Parameter berawalan satu tanda bintang mengumpulkan seluruh argumen posisi yang berlebih menjadi satu tuple. Nama args hanyalah kebiasaan penulisan, sehingga bentuk *angka sama sahnya. Fungsi yang memuat parameter semacam ini dapat dipanggil dengan nol argumen atau lebih.
def total(*angka):
hasil = 0
for a in angka:
hasil += a
return hasil
print(total(1, 2, 3))
print(total(10, 20, 30, 40))
print(total())6
100
0Tiga pemanggilan menghasilkan tiga nilai karena angka menerima tuple dengan panjang berbeda, termasuk tuple kosong pada pemanggilan tanpa argumen. Di dalam badan fungsi, angka diperlakukan seperti tuple biasa, sehingga perulangan dan sum() bekerja tanpa penyesuaian apa pun.
def contoh(*angka):
print(type(angka).__name__)
contoh(1, 2)tupleJenis datanya dapat dibuktikan langsung, yaitu tuple. Konsekuensinya, isi angka tidak dapat diubah setelah terkumpul, dan penambahan item dilakukan dengan membuat tuple baru atau mengonversinya ke list terlebih dahulu.
Parameter *args paling tepat dipakai ketika jumlah masukannya memang tidak terbatas, misalnya penjumlahan atau penggabungan. Fungsi yang parameternya jelas di muka sebaiknya tetap menuliskannya secara eksplisit, karena daftar parameter terbaca pada baris def dan kekurangannya langsung ditolak. Pembungkusan yang berlebihan justru menyembunyikan antarmuka fungsi dari pembacanya.
Menerima argumen kata kunci dengan **kwargs#
Parameter berawalan dua tanda bintang mengumpulkan argumen kata kunci yang berlebih menjadi satu dictionary, dengan nama argumen sebagai kuncinya. Pola ini berguna untuk opsi yang jumlah dan namanya tidak dapat dipastikan di muka.
def tampilkan_info(**info):
for kunci, nilai in info.items():
print(kunci, "=", nilai)
tampilkan_info(nama="Ali", kota="Bandung")nama = Ali
kota = BandungSetiap pasangan kunci=nilai pada pemanggilan masuk ke dictionary info. Urutan cetakannya mengikuti urutan penulisan argumen, karena dictionary menjaga urutan penyisipannya. Kehadiran sebuah kunci diperiksa dengan operator in sebelum kuncinya diakses, sehingga kunci yang wajib ada diverifikasi dengan jelas. Parameter **kwargs menghasilkan dictionary kosong apabila tidak ada argumen kata kunci yang dikirim.
Menggabungkan parameter biasa, *args, dan **kwargs#
Ketiganya dapat dipakai dalam satu fungsi dengan urutan tetap, yaitu parameter biasa terlebih dahulu, kemudian *args, lalu **kwargs. Argumen posisi mengalir ke parameter biasa lalu ke *args, sedangkan argumen kata kunci yang tidak cocok dengan parameter biasa terkumpul di **kwargs.
def laporan(judul, *angka, **opsi):
print(judul, sum(angka))
if "satuan" in opsi:
print("satuan:", opsi["satuan"])
laporan("Total", 2, 4, 6)
laporan("Total", 1, 1, satuan="kg")Total 12
Total 2
satuan: kgPemanggilan pertama mengirim tiga angka tanpa opsi, sehingga baris satuan tidak dicetak. Pemanggilan kedua menyisipkan satuan="kg" yang tidak memiliki parameter tetap, sehingga masuk ke opsi. Pola ini lazim dipakai fungsi yang mencatat atau memproses data dengan bentuk bebas.
Pola penerusan argumen#
Tanda bintang juga bekerja pada arah sebaliknya, yaitu membuka kembali tuple dan dictionary menjadi argumen. Fungsi wrapper yang menerima *args, **kwargs lalu meneruskannya dengan fungsi_lain(*args, **kwargs) dapat membungkus fungsi apa pun tanpa mengetahui parameternya.
def catat(*args, **kwargs):
print("diteruskan:", args, kwargs)
def utama(*args, **kwargs):
catat(*args, **kwargs)
utama(1, 2, mode="cepat")diteruskan: (1, 2) {'mode': 'cepat'}Fungsi utama menerima 1, 2, dan mode="cepat", lalu meneruskannya utuh kepada catat. Pembungkus semacam ini menjadi dasar decorator dan pencatatan (logging), karena parameternya mengikuti fungsi yang dibungkus dan tidak perlu disalin satu per satu.
Penerusan utuh menuntut disiplin yang sama pada fungsi yang dibungkus. Kesalahan tipe atau jumlah argumen baru terlihat ketika fungsi akhir menolaknya, karena lapisan pembungkus tidak memeriksa apa pun. Meskipun demikian, pola ini menjaga pembungkus tetap berguna bagi fungsi mana pun, sehingga dipakai luas pada decorator, pencatatan, dan pemanggilan berlapis.
Membuka nilai menjadi argumen saat memanggil#
Di sisi pemanggil, satu tanda bintang membuka list atau tuple menjadi argumen posisi, sedangkan dua tanda bintang membuka dictionary menjadi argumen kata kunci. Data yang sudah berbentuk urutan dapat disalurkan ke fungsi berparameter tetap tanpa mengindeksnya satu per satu.
def kuadrat_jumlah(x, y):
return x * x + y * y
nilai = [3, 4]
print(kuadrat_jumlah(*nilai))
opsi = {"x": 2, "y": 5}
print(kuadrat_jumlah(**opsi))25
29List nilai dibuka menjadi dua argumen posisi, dan dictionary opsi dibuka menjadi argumen kata kunci x serta y. Panjang data wajib cocok dengan parameter fungsi, sebab ketidakcocokan tetap ditolak oleh pemanggilan.
Kesalahan umum#
Kesalahan pertama adalah membuka data yang panjangnya tidak cocok. Fungsi sambung menuntut tiga argumen, sedangkan listnya hanya memuat dua, sehingga pemanggilan ditolak dengan pesan yang menyebut parameter yang kurang.
def sambung(x, y, z):
return x + y + z
try:
sambung(*[1, 2])
except TypeError as e:
print(type(e).__name__, str(e))TypeError sambung() missing 1 required positional argument: 'z'Kesalahan kedua adalah mengira args dan kwargs adalah nama khusus. Keduanya hanyalah nama parameter biasa, dan yang menentukan perilakunya adalah tanda bintang di depannya, sehingga nama lain tetap sah. Penulisan *args dan **kwargs dipertahankan karena menjadi kebiasaan bersama di komunitas Python, dan kode yang membaca kebiasaan itu lebih mudah dipahami.
Kesalahan ketiga adalah mengubah isi args seperti list. Parameter *args menghasilkan tuple yang tidak dapat diubah, sehingga perintah seperti args.append(1) menimbulkan error AttributeError. Pengubahannya dilakukan dengan membuat tuple baru atau mengonversinya melalui list(args) terlebih dahulu.
Ringkasan#
- Parameter
*argsmengumpulkan argumen posisi berlebih menjadi tuple, sedangkan**kwargsmengumpulkan argumen kata kunci menjadi dictionary. - Urutan parameter pada satu
deftetap, yaitu parameter biasa terlebih dahulu, lalu*args, dan terakhir**kwargs. - Tanda bintang pada pemanggilan membuka urutan dan dictionary menjadi argumen, sehingga fungsi wrapper dapat meneruskan argumen apa adanya.
- Jumlah argumen hasil pembukaan wajib cocok dengan parameter fungsi, atau pemanggilannya ditolak dengan
TypeError.
Referensi#
- More Control Flow Tools — Python Software Foundation — Bagian tutorial resmi tentang daftar argumen sembarang dengan *args.
- More Control Flow Tools — Python Software Foundation — Bagian tutorial resmi tentang pembukaan argumen pada pemanggilan.
- Calls — Python Software Foundation — Referensi bahasa untuk semantik pemanggilan dan tanda bintang.