Program kita kini bisa menghitung, tetapi masih galak terhadap penggunanya: satu ketikan dua belas merobohkan seluruh sesi dengan traceback, dan jawaban acak pada pertanyaan hitung lagi langsung mengakhiri program. Pada bagian ini kita melengkapi seluruh titik masukan dengan validasi bercorak coba-ulang (retry loop): input yang tidak valid ditolak dengan pesan, lalu pengguna diminta mencoba lagi — program tidak pernah crash karena salah ketik.
Dua Pola Validasi Input #
Validasi input pengguna pada program interaktif umumnya memakai salah satu dari dua pola berikut:
- Daftar putih (whitelist): cocok untuk pilihan yang jumlahnya terbatas. Pilihan menu
1-5dan jawabany/tdiperiksa dengan operatorinterhadap tuple nilai yang sah. Input di luar daftar pasti ditolak. try/exceptdengan coba-ulang: cocok untuk konversi tipe. Fungsifloat()membangkitkanValueErrorketika teks bukan angka; kita menangkap exception itu, mencetak pesan, lalu mengulang pembacaan.
Kedua pola hidup di dalam function pembaca itu sendiri, bukan di jalankan(). Hasilnya adalah kontrak yang kuat: baca_pilihan() dijamin hanya mengembalikan salah satu dari "1" sampai "5", dan baca_angka() dijamin mengembalikan float. Setelah kontrak ini berlaku, jalankan() tidak lagi memerlukan pemeriksaan if pilihan not in OPERASI — percaya pada kontrak function adalah inti dari refactor pada bagian ini.
Kode Lengkap Bagian 3 #
"""Kalkulator Terminal - validasi input.
Bagian 3: validasi pilihan menu, angka, dan jawaban y/t
dengan pola coba-ulang hingga input valid.
"""
def tampilkan_menu():
"""Cetak daftar operasi yang tersedia."""
print("=== Kalkulator Terminal ===")
print("1. Tambah")
print("2. Kurang")
print("3. Kali")
print("4. Bagi")
print("5. Keluar")
def baca_pilihan():
"""Baca nomor operasi; ulangi sampai pengguna memasukkan 1-5."""
while True:
pilihan = input("Pilih operasi (1-5): ").strip()
if pilihan in ("1", "2", "3", "4", "5"):
return pilihan
print(f"Pilihan '{pilihan}' tidak dikenal. Masukkan angka 1-5.")
def baca_angka(label):
"""Baca satu angka; ulangi sampai input dapat dikonversi menjadi float."""
while True:
teks = input(f"{label}: ").strip()
try:
return float(teks)
except ValueError:
print(f"'{teks}' bukan angka yang valid. Coba lagi.")
def tanya_lagi():
"""Tanyakan apakah pengguna ingin menghitung lagi; terima hanya y atau t."""
while True:
jawaban = input("Hitung lagi? (y/t): ").strip().lower()
if jawaban in ("y", "t"):
return jawaban == "y"
print("Jawaban harus 'y' atau 't'.")
def tambah(a, b):
"""Kembalikan hasil a + b."""
return a + b
def kurang(a, b):
"""Kembalikan hasil a - b."""
return a - b
def kali(a, b):
"""Kembalikan hasil a * b."""
return a * b
def bagi(a, b):
"""Kembalikan hasil a / b, atau None bila pembagi bernilai nol."""
if b == 0:
print("Error: pembagian dengan nol tidak diperbolehkan.")
return None
return a / b
OPERASI = {
"1": ("+", tambah),
"2": ("-", kurang),
"3": ("*", kali),
"4": ("/", bagi),
}
def jalankan():
"""Jalankan loop utama kalkulator."""
while True:
tampilkan_menu()
pilihan = baca_pilihan()
if pilihan == "5":
break
simbol, fungsi = OPERASI[pilihan]
a = baca_angka("Angka pertama")
b = baca_angka("Angka kedua")
hasil = fungsi(a, b)
if hasil is not None:
print(f"Hasil: {a:g} {simbol} {b:g} = {hasil:g}")
if not tanya_lagi():
break
print("Terima kasih telah menggunakan Kalkulator Terminal.")
if __name__ == "__main__":
jalankan()Perubahan terpenting ada pada tiga function pembaca; sisanya tetap. Mari kita bedah:
- Baris 18-24 (
def baca_pilihan():): loopwhile Truemembungkus pembacaan. Metode.strip()pada baris 21 membuang spasi di awal dan akhir ketikan, sehingga" 1 "diterima. Baris 22 memeriksa keanggotaan dalam tuple nilai sah; baris 24 mencetak pesan lalu loop berputar kembali ke prompt. Pergantianreturndi baris 23 adalah satu-satunya jalan keluar dari loop. - Baris 27-34 (
def baca_angka(label):): polatry/exceptdari Chapter try dan except. Barisreturn float(teks)di dalam bloktrysekaligus mengembalikan angka dan mengakhiri loop; bila konversi gagal, klausaexcept ValueErrormenangkap, mencetak pesan, dan loop mengulang pembacaan. - Baris 37-43 (
def tanya_lagi():): gabungan dua pola —.strip().lower()merapikan jawaban, daftar putih("y", "t")menolak jawaban lain seperti"ya", dan hasil dikembalikan sebagai boolean lewat perbandinganjawaban == "y". - Baris 77-98 (
def jalankan():): bandingkan dengan Bagian 2 — blokif pilihan not in OPERASI: ... continuesudah hilang. Baris 86 (simbol, fungsi = OPERASI[pilihan]) kini boleh mengakses dictionary langsung karenabaca_pilihan()menjamin pilihan selalu valid. Ketidaksetaraan hasilif hasil is not Nonetetap ada sementara, menunggu refactor Bagian 4.
Mencoba Program #
Uji ketiga validasi sekaligus dalam satu sesi: pilihan menu yang salah, angka yang salah, lalu perhitungan yang berhasil:
printf 'sembilan\n1\ndua belas\n12\n3\nt\n' | python3 main.pyOutput yang Dihasilkan:
=== Kalkulator Terminal ===
1. Tambah
2. Kurang
3. Kali
4. Bagi
5. Keluar
Pilih operasi (1-5): Pilihan 'sembilan' tidak dikenal. Masukkan angka 1-5.
Pilih operasi (1-5): Angka pertama: 'dua belas' bukan angka yang valid. Coba lagi.
Angka pertama: Angka kedua: Hasil: 12 + 3 = 15
Hitung lagi? (y/t): Terima kasih telah menggunakan Kalkulator Terminal.Perhatikan urutannya: pesan penolakan tampil, prompt diulang, dan program tetap hidup. Sekarang uji validasi jawaban pada tanya_lagi():
printf '2\n8\n3\nya\ny\n5\n' | python3 main.pyOutput yang Dihasilkan:
=== Kalkulator Terminal ===
1. Tambah
2. Kurang
3. Kali
4. Bagi
5. Keluar
Pilih operasi (1-5): Angka pertama: Angka kedua: Hasil: 8 - 3 = 5
Hitung lagi? (y/t): Jawaban harus 'y' atau 't'.
Hitung lagi? (y/t): === Kalkulator Terminal ===
1. Tambah
2. Kurang
3. Kali
4. Bagi
5. Keluar
Pilih operasi (1-5): Terima kasih telah menggunakan Kalkulator Terminal.Jawaban ya ditolak karena bukan y, prompt diulang, dan y berikutnya diterima.
Ringkasan Bagian 3 #
Seluruh titik masukan kini tervalidasi: menu menolak pilihan asing, angka menolak teks yang tak bisa dikonversi, dan jawaban y/t tidak lagi menebak-nebak. Satu bau kode masih tersisa: bagi() mencetak pesan galat sekaligus mengembalikan None, dan jalankan() harus memeriksa hasil is not None — logika hitung masih bercampur dengan urusan input/output. Refactor pada Bagian 4 memisahkan keduanya dan membekali proyek dengan test. Berkas lengkap bagian ini dapat diunduh di bagian bawah halaman.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
main.py
Unduh berkas"""Kalkulator Terminal - validasi input.
Bagian 3: validasi pilihan menu, angka, dan jawaban y/t
dengan pola coba-ulang hingga input valid.
"""
def tampilkan_menu():
"""Cetak daftar operasi yang tersedia."""
print("=== Kalkulator Terminal ===")
print("1. Tambah")
print("2. Kurang")
print("3. Kali")
print("4. Bagi")
print("5. Keluar")
def baca_pilihan():
"""Baca nomor operasi; ulangi sampai pengguna memasukkan 1-5."""
while True:
pilihan = input("Pilih operasi (1-5): ").strip()
if pilihan in ("1", "2", "3", "4", "5"):
return pilihan
print(f"Pilihan '{pilihan}' tidak dikenal. Masukkan angka 1-5.")
def baca_angka(label):
"""Baca satu angka; ulangi sampai input dapat dikonversi menjadi float."""
while True:
teks = input(f"{label}: ").strip()
try:
return float(teks)
except ValueError:
print(f"'{teks}' bukan angka yang valid. Coba lagi.")
def tanya_lagi():
"""Tanyakan apakah pengguna ingin menghitung lagi; terima hanya y atau t."""
while True:
jawaban = input("Hitung lagi? (y/t): ").strip().lower()
if jawaban in ("y", "t"):
return jawaban == "y"
print("Jawaban harus 'y' atau 't'.")
def tambah(a, b):
"""Kembalikan hasil a + b."""
return a + b
def kurang(a, b):
"""Kembalikan hasil a - b."""
return a - b
def kali(a, b):
"""Kembalikan hasil a * b."""
return a * b
def bagi(a, b):
"""Kembalikan hasil a / b, atau None bila pembagi bernilai nol."""
if b == 0:
print("Error: pembagian dengan nol tidak diperbolehkan.")
return None
return a / b
OPERASI = {
"1": ("+", tambah),
"2": ("-", kurang),
"3": ("*", kali),
"4": ("/", bagi),
}
def jalankan():
"""Jalankan loop utama kalkulator."""
while True:
tampilkan_menu()
pilihan = baca_pilihan()
if pilihan == "5":
break
simbol, fungsi = OPERASI[pilihan]
a = baca_angka("Angka pertama")
b = baca_angka("Angka kedua")
hasil = fungsi(a, b)
if hasil is not None:
print(f"Hasil: {a:g} {simbol} {b:g} = {hasil:g}")
if not tanya_lagi():
break
print("Terima kasih telah menggunakan Kalkulator Terminal.")
if __name__ == "__main__":
jalankan()