Ini adalah kursus pertama di Ilmu Komputer Universitas: prinsip dasar pemrograman
, diajarkan menggunakan Python 3. Kursus ini tidak memerlukan pengalaman pemrograman sebelumnya. Setiap program dalam
modul ini lengkap dan dapat dijalankan — ketik, jalankan, ubah satu baris, dan prediksi
apa yang berubah sebelum menjalankannya lagi. Siklus prediksi-lalu-jalankan inilah seluruh keterampilan tersebut.
Kursus ini merupakan sebuah tangga:
Unit 1.1 hingga 1.3 membangun mekanisme: nilai dan jenis, pemilihan, iterasi.
Unit 1.4 mengemas pekerjaan ke dalam fungsi.
Unit 1.5 dan 1.6 menambahkan koleksi standar dan file dengan penanganan kesalahan.
Unit 1.7 adalah disiplin utama: menguraikan masalah, pengujian, dan perbaikan kesalahan.
Cara membaca setiap unit: sebuah cerita singkat menjelaskan mengapa hal itu penting; sebuah gambar atau aturan praktis
datang sebelum sintaks apa pun; kemudian aturan yang presisi; lalu contoh kerja yang semakin sulit,
setiap satu memiliki jejak yang dapat Anda periksa dengan menjalankan kode; kemudian kesalahan yang sebenarnya
dibuat orang; lalu ringkasan tiga baris. Setiap contoh di sini dapat diperiksa dengan cara kedua —
menjalankannya. Membaca kode tanpa menjalankannya seperti membaca notasi musik tanpa
mendengarkannya.
Aplikasi belanja menampilkan "4.20" — apakah itu teks atau angka? Jika itu teks, menambahkan dua
harga menghasilkan "4.203.50"; jika itu angka, hasilnya 8.7. Yang mana yang terjadi ditentukan
oleh tipe, dan seluruh unit 1.1 adalah belajar melihat tipe sebelum Anda
menjalankan apa pun.
Sebuah nilai memiliki tipe, dan tipe menentukan apa yang dapat Anda lakukan dengannya: int (bilangan bulat
), float (desimal), str (teks), bool (True/False). Fungsi type(...)
menyebutkan tipe dari setiap nilai — tanyakan secara bebas saat belajar.
age = 21 # int
price = 4.20 # float
name = "Ada" # str
open_ = True # bool
print(type(age)) # <class 'int'>
Variabel adalah nama yang dikaitkan dengan nilai; penugasan age = 22 mengikat ulang nama tersebut —
tidak pernah mengedit nilai lama. Peta mental yang layak untuk dijaga sepanjang masa kuliah:
Nama adalah label pada kotak; ekspresi membaca kotak dan membuat kotak baru
Membaca ekspresi berarti "buka kotak, hitung, tutup kotak baru": count * 3.50
dengan count = 6 membuka kotak int 6 dan kotak float 3.50, dan pencampuran Python
aturan mendorong int — hasilnya adalah float21.0, bukan int 21.
Konversi bersifat eksplisit: int("21") adalah 21, tetapi "4" + 2 adalah TypeError — Python
menolak menebak apakah Anda bermaksud "42" atau 6. Keluaran dengan print(...); masukan dengan
input(...), yang selalu mengembalikan string, sehingga angka perlu dikonversi:
Contoh terpecahkan 1 (mesin kasir kafe).count = int(input("Coffees? ")), kemudian
print("Total:", count * 3.50). Pada 6 cangkir kopi ini mencetak Total: 21.0 — yaitu .0
menandai float, karena int * float didorong ke float. Memantau jenis apa yang keluar
dari sebuah ekspresi adalah kebiasaan utuh dari unit 1.1. Telusuri dengan cara keadaan: input mengembalikan
string "6"; int(...) membuka kotak baru yang berisi int 6; perkalian
membuat kotak float baru 21.0; print menampilkannya.
Contoh terpecahkan 2 (kecelakaan klasik, diperbaiki). Sebuah pencetak spanduk menggabungkan hitungan
kepada sebuah pesan:
Jalankan dan Python akan memicu TypeError: can only concatenate str (not "int") to str —
aturan menolak menebak. Perbaikan tersebut menyebutkan konversi secara eksplisit:
print("Sold " + str(count) + " today"), atau yang lebih bersih print("Sold", count, "today"), which inserts the spaces for you. The lesson to carry: + berarti penjumlahan
untuk angka, penggabungan untuk string, dan never campur diam-diam.
Kesalahan umum. Melupakan bahwa input() selalu menghasilkan string, sehingga
input() * 2 mengulang teks daripada melipatgandakan angka. Menulis 4.20 + 6 dan
mengharapkan jawaban int — setiap float dalam ekspresi menghasilkan float. Percaya
0.1 + 0.2 == 0.3 (ini adalah False; pembulatan biner — unit 1.2 menunjukkan perbaikannya).
Ringkasan: empat jenis dasar menentukan setiap operasi; nama adalah tag, penugasan mengikat ulang;
ekspresi mencampur tipe dengan promosi ke float; konversi bersifat eksplisit dan
input() membutuhkan satu.
Pintu gerbang taman hiburan harus menagih anak-anak, orang dewasa, dan lansia secara berbeda — satu
program, beberapa jalur. Seleksi adalah cara program memilih: if, elif,
else menjalankan blok hanya ketika suatu kondisi terpenuhi.
Usia 70, mahasiswa: cabang pertama yang benar menentukan harga
Kondisi adalah ekspresi boolean apa pun; perbandingan (==, !=, <, >=) dan
logika (and, or, not) membangunnya. Dua aturan membuat setiap keputusan mudah dibaca:
Cabang diuji dari atas ke bawah; cabang pertama yang benar menang dan sisanya
dilewati.
Indentasi bukan sekadar hiasan — ia ADALAH blok. Satu spasi ekstra mengubah garis mana
yang termasuk dalam cabang tersebut.
temp = 37.5
if temp >= 38:
print("Fever")
elif temp >= 36 and temp < 38:
print("Normal")
else:
print("Low")
Contoh terpecahkan 1 (harga bioskop). Di bawah 12 atau 65+ bayar 5, mahasiswa membayar 7,
semua orang lain 10:
age = int(input("Age? "))
student = input("Student? y/n ") == "y"
if age < 12 or age >= 65:
price = 5
elif student:
price = 7
else:
price = 10
print("Pay", price)
Urutan itu penting: cabang pertama yang benar menang, itulah sebabnya pengecekan usia mendahului
pengecekan mahasiswa — mahasiswa berusia 70 seharusnya membayar 5, dan pengurutan ini menyatakannya. Jalankan
dengan 70 dan y untuk melihat jalur paling kiri pada diagram alir diambil.
Contoh terpecahkan 2 (rentang nilai, ditingkatkan). Rangka yang sama, kini dengan rantai
di mana setiap elif hanya memerlukan satu perbandingan, karena uji di atasnya sudah
gagal:
score = int(input("Score? "))
if score >= 80:
band = "A"
elif score >= 70:
band = "B"
elif score >= 60:
band = "C"
else:
band = "F"
print("Band:", band)
Di 79 uji pertama gagal, kedua berhasil: Band: B. Peningkatan ke
perhatian: elif score >= 70 tidak juga membutuhkan and score < 80 — mencapai baris
tersebut sudah membuktikan skor berada di bawah 80. Mempercayai alur jatuh seperti ini adalah
yang membuat rantai pendek; menguji semuanya kembali adalah versi pemula yang lebih panjang dan salah.
versi.
Perbandingan bilangan floating-point memerlukan kehati-hatian: 0.1 + 0.2 == 0.3 adalah False (biner
pembulatan), jadi bandingkan terhadap toleransi: abs(x - y) < 1e-9.
Kesalahan umum. Menulis = di mana seharusnya == — bug klasik, dan Python
menolaknya dalam kondisi (SyntaxError) tepat karena hal itu sangat umum. Menguji
kasus khusus setelah kasus umum, sehingga kasus umum selalu menang. Menggunakan
elif dengan kondisi yang tidak pernah dapat dicapai karena cabang sebelumnya sudah
menangkapnya.
Ringkasan: kondisi memilih jalur, menang-nyata-pertama, indentasi adalah blok; urutkan
uji dari spesifik-ke-umum; titik-mengambang dibandingkan melalui toleransi, bukan oleh ==.
1.3
Iterasi: melakukannya lagi
Membayar tagihan 5,000 secara manual adalah sebuah karier; dengan perulangan ia menjadi program. Iterasi
mengulang pekerjaan: perulangan for menelusuri urutan yang diketahui; perulangan while berjalan selama
syarat terpenuhi. Pertanyaan desainnya selalu: apakah Anda tahu berapa banyak trip, atau
apakah sebuah syarat yang menentukannya?
total = 0
for i in range(1, 101): # 1..100 — range stops BEFORE its end
total += i
print(total) # 5050
Gunakan for ketika jumlah trip diketahui; gunakan while ketika syarat yang menentukannya. Setiap
while membutuhkan tiga hal yang terlihat dalam kode: awal variabel, kondisi,
dan sesuatu di dalamnya yang bergerak menuju keluar — jika tidak, itu adalah loop tak terbatas.
loop**.
Tabel jejak untuk loop faktorial
n = 5
factorial = 1
while n > 1:
factorial *= n
n -= 1 # the step toward exiting
print(factorial) # 120
Tabel jejak adalah kebiasaan pengecekan kursus untuk loop: ikuti
variabel-variabelnya dari putaran ke putaran, di atas kertas terlebih dahulu. Untuk loop faktorial:
(n=5, f=1) → (4, 5) → (3, 20) → (2, 60) → (1, 120). Bangun tabel secara manual, lalu
tambahkan print(n, factorial) di dalam loop dan biarkan Python mengoreksi Anda.
Contoh terpecahkan 2 (pencarian dengan break, ditingkatkan). Temukan kelipatan pertama dari
7 yang lebih besar dari 100 — jumlah trip tidak diketahui, syarat yang menentukannya:
n = 100
while True:
if n % 7 == 0:
break # found it — leave the loop now
n += 1
print(n) # 105
Jejaknya singkat: 100, 101, …, 104 semuanya gagal tes; 105 lolos dan break
keluar. break meninggalkan loop lebih awal; continue melompat ke putaran berikutnya. Keduanya adalah
alat keterbacaan — loop yang harus memindai hingga menemukan sesuatu, lalu berhenti, terbaca
terbaik dengan break. Peningkatan lebih lanjut, menggandakan uang: pada 5% per tahun, berapa lama
1000 butuh untuk mencapai 2000?
balance = 1000.0
years = 0
while balance < 2000.0: # the condition itself is the goal
balance *= 1.05
years += 1
print(years, round(balance, 2)) # 15 2078.93
Lima belas tahun, dan loop berhenti saat syarat berubah — tabel jejak
akan menunjukkan saldo melewati garis di 2078.93, bukan mendarat tepat di 2000.
Kesalahan umum. Mengedit daftar (unit 1.5) atau variabel perulangan yang Anda
for-berputar. range(1, 100) ketika 100 seharusnya digunakan — akhir tidak termasuk.
A while yang langkah keluarannya hilang atau dikomentari: kondisi tidak pernah berubah,
dan program macet.
Ringkasan: for untuk jumlah perjalanan yang diketahui, while untuk kondisi; setiap loop menunjukkan awal,
syarat dan langkah; jejak di atas kertas, lalu cetak-tingkat; break dan continue untuk
keluaran dini yang bersih.
1.4
Fungsi: memberi nama pekerjaan sekali
Perhitungan harga yang sama muncul di lima tempat; aturan pajak berubah; empat dari
lima diperbarui. A function mengemas pekerjaan di balik nama agar ditulis
sekali dan dipercaya di mana saja: parameter masuk, a return value keluar. def
mendefinisikan; pemanggilan menjalankan.
def total_price(count, unit=3.50):
"""Return the total for count items at unit price."""
return count * unit
print(total_price(6)) # 21.0
print(total_price(6, unit=4.0)) # 24.0
Definisi memberikan a parameter (count, unit); pemanggilan menyediakan a
argument (6). Nilai default (unit=3.50) membuat argumen opsional.
return mengembalikan nilai dan mengakhiri pemanggilan; printing is not returning — a
fungsi tanpa return mengembalikan None, dan pemanggil yang mencoba aritmatika padanya
mendapatkan a TypeError.
Panggilan bersarang: Caller berhenti hingga nilai kembali
Setiap pemanggilan mendapatkan a local scope: nama di dalamnya tidak terlihat
di luar, dan menghilang ketika panggilan berakhir. Jejak panggilan untuk panggilan bersarang membaca:
pemanggil berhenti → penerima berjalan → nilai pengembalian mendarat di pemanggil.
Contoh terpecahkan 1 (pesanan termasuk biaya).
def add_fee(amount):
"""Return amount plus a fixed 3 pence fee."""
return amount + 3
def order_total(unit_pence, quantity):
"""Return the order total: subtotal plus the fixed fee."""
return add_fee(unit_pence * quantity)
print(order_total(250, 4)) # 1003
Kontrak dalam docstring itu penting: pence bulat masuk, pence bulat keluar. Melacak
order_total(250, 4): subtotal 1000, add_fee mengembalikan 1003 — dan bingkai
diagram di atas menunjukkan jeda dan serah terima.
Contoh terpecahkan 2 (algoritma nyata di dalam fungsi kecil, ditingkatkan).is_prime(n) mengembalikan True ketika tidak ada dari 2 hingga $\sqrt{n}$ yang membagi n:
def is_prime(n):
if n < 2:
return False
d = 2
while d * d <= n: # only test up to the square root
if n % d == 0:
return False # found a divisor — answer known, stop
d += 1
return True
print([p for p in range(2, 30) if is_prime(p)])
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Dua kebiasaan fungsi bertemu di sini: return awal mengakhiri panggilan segera setelah jawaban
diketahui (tidak perlu variabel flag), dan batas perulangan d * d <= n berasal dari
penurunan — jika $n = a \times b$ dengan $a \le b$, maka $a \le \sqrt{n}$, sehingga pengujian melebihi $\sqrt{n}$
menguji kembali pembagi yang sudah dilihat. Jalankan: daftar tersebut adalah tepat bilangan prima di bawah 30.
Kesalahan umum. Mencetak di dalam fungsi alih-alih mengembalikan, sehingga hasilnya
tidak dapat digunakan kembali. Lupa return pada salah satu cabang — jalur itu secara diam-diam menghasilkan
None. Menjangkau ke lokal fungsi dari luar; mereka hilang ketika panggilan
berakhir.
Ringkasan: def sekali, panggil di mana saja; parameter masuk, satu nilai keluar melalui return;
pengembalian awal mengakhiri panggilan; lokal hidup dan mati bersama panggilan; docstrings menyatakan
kontrak.
Kasir kafe memerlukan pesanan harian yang tertata, menu berdasarkan nama, lokasi yang
tidak boleh bergeser, dan minuman unik hari ini. Empat pekerjaan, empat wadah — memilih
di antara mereka adalah keputusan desain unit 1.5.
List adalah urutan yang tertata dan dapat diubah: marks = [72, 85, 61], diindeks
dari 0, dipotong dengan marks[1:3]. Dictionary memetakan kunci ke nilai:
price = {"flat white": 3.5, "tea": 2.8}, dibaca dan ditulis berdasarkan kunci. Tuple
adalah urutan tetap (53.1, -1.5) — cocok untuk koordinat yang tidak boleh berubah. Set
menyimpan item unik tanpa urutan: {"a", "b"}.
marks = [72, 85, 61]
marks.append(90) # [72, 85, 61, 90]
best = max(marks) # 90
average = sum(marks) / len(marks) # 77.0
Aliasing: dua nama, satu list
Penugasan tidak pernah menyalin: a = [1]; b = a; b.append(2) membuat a[1, 2] — list
dibagikan, namanya tidak. Aliasing ini adalah kotak unit 1.1 lagi, sekarang
dengan dua label pada satu kotak, dan hal ini juga menjelaskan aturan berikutnya: memodifikasi list saat
mengiterasi melompati elemen — iterasikan salinan (for m in marks[:]) atau buat
list baru.
.get(key, 0) dari dictionary menyediakan 0 untuk pengamatan pertama — idiom yang
membuat perhitungan menjadi satu baris. Verifikasi manual: "tea" muncul tiga kali dalam orders,
dan rekapitulasi yang dicetak mengonfirmasi hal itu.
Contoh terpecahkan 2 (penjual terbaik hari ini, ditingkatkan). Berbekal rekapitulasi,
laporkan item teratas dan jumlahnya:
best = max(tally, key=tally.get)
print(best, tally[best]) # tea 3
Argumen key=tally.get meminta max untuk membandingkan item berdasarkan jumlah mereka daripada
secara alfabetis — trik key= yang sama mengurutkan koleksi apa pun berdasarkan ukuran tertentu. Hal
peningkatan ini penting: program nyata menggabungkan alat-alat ini (menghitung, lalu mengurut) daripada
memindai ulang orders dua kali.
Memilih koleksi adalah keputusan desain: urutan + duplikat → list; pencarian berdasarkan
nama → dictionary; pengelompokan tetap → tuple; keunikan → set.
Kesalahan umum. Mengakses tally[item] += 1 pada kunci yang belum ada di dictionary
(KeyError) — .get adalah solusinya. Mengharapkan set atau dictionary untuk mengingat urutan.
Menganggap bahwa b = a menyalin sebuah list; ia hanya membuat referensi (alias).
Ringkasan: empat wadah untuk empat tugas; penugasan berbagi referensi, bukan menyalin; .get
membuat penghitungan aman; key= membuat peringkat menjadi satu baris kode.
Kafe tutup, listrik mati — dan rekap pagi itu hanya terselamat jika
program menuliskannya ke disk. File bertahan lebih lama daripada program. with open(path) as f: opens, closes on exit, and reads text; open(path, "w") menulis
(dan mengosongkannya terlebih dahulu — kecelakaan klasik).
with open("log.txt", "w") as f:
f.write("opened\n")
with open("log.txt") as f:
for line in f:
print(line.rstrip()) # rstrip removes the trailing newline
Blok with adalah pengaman: apa pun yang terjadi di dalamnya, file akan tertutup.
Membaca memberikan baris berserta karakter baris baru, sehingga .rstrip() wajib ada dalam setiap perulangan.
Kesalahan adalah nilai yang Python bangkitkan sebagai kecualian: FileNotFoundError,
ValueError, KeyError, TypeError. try/except menangkap tipe bernama — jangan pernah menggunakan
except: polos yang menyembunyikan bug nyata.
Contoh terpecahkan 1 (file pengaturan yang hilang). Membaca ukuran teks dari file pengaturan
file yang mungkin hilang, atau mungkin tidak berisi bilangan bulat:
try:
with open("settings.txt") as f:
size = int(f.read().strip())
except FileNotFoundError:
size = 12 # no file yet: a sensible default
except ValueError:
size = 12 # the file holds "big", not a number
print("Text size", size)
Jalankan tiga kali — dengan 16 dalam file, tanpa file, dan dengan big dalam
file — dan mencetak ukuran yang dapat digunakan setiap kali, dari tiga rute berbeda. Inilah bentuk kode yang tangguh: satu cara yang logis
beberapa jalan menuju sana. Tangani kesalahan yang Anda harapkan, di mana Anda dapat merespons
padanya; biarkan sisanya crash dengan keras.
Contoh terpecahkan 2 (loop input tangguh, eskalasi). Minta hingga pengguna mengetik
bilangan bulat:
Berikan ke x lalu 4: perjalanan pertama memicu, ditangkap, mencetak pesan, dan
while True meminta lagi; perjalanan kedua dari int(...) berhasil dan return keluar
dari loop dan fungsi dalam satu gerakan. Tiga unit bergabung di sini — loop (1.3),
kontrak fungsi (1.4) dan pengecualian (1.6) — yang merupakan inti dari
eskalasi.
Kesalahan umum. Memasukkan ke open(path, "w") pada jalur yang salah: file dibuat atau
dikosongkan sebelum Anda menyadari. Menangkap Exception secara luas dan melanjutkan dengan
keadaan rusak. Melupakan .rstrip(), sehingga output menampilkan baris dengan spasi ganda.
Ringkasan: Gunakan with open(...) untuk membaca dan menulis; "w" kosongkan terlebih dahulu;
pengecualian adalah nilai — tangkap tipe bernama yang Anda harapkan, gunakan alternatif yang masuk akal, biarkan
sisa crash.
1.7
Dekomposisi, pengujian, dan perbaikan kode
Dua tim menulis aplikasi yang sama; satu selesai dalam seminggu, satu lagi tenggelam selama sebulan. Perbedaan
bukanlah kecepatan mengetik — melainkan kode tim cepat dibangun dari potongan-potongan kecil
yang masing-masing dapat dibuktikan kebenarannya, sementara tim lambat melakukan perbaikan pada seluruh aplikasi sekaligus.
Unit 1.7 adalah disiplin tersebut.
Dekomposisi memecah masalah menjadi fungsi dengan satu tugas masing-masing — setiap bagian kecil
cukup untuk diuji secara terpisah. Pengujian membandingkan output aktual sebuah fungsi dengan
hasil yang diharapkan, pada batas-batas: nol, satu, kosong, negatif, sangat besar.
Sebuah assert yang tidak pernah aktif adalah tes yang berhasil. Tulis tes sebelum Anda menulis
tubuh fungsi jika memungkinkan — mereka adalah kontrak yang dieksekusi, dan siklus di atas
(merah → hijau → refaktor) adalah kebiasaan yang berjalan terus-menerus.
Contoh terpecahkan 1 (perluas tes dengan fungsi). Perpanjang order_total dengan sebuah
diskon 10% di atas £10 — tes ditulis terlebih dahulu, pada batas baru:
Periksa tes tengah secara manual: subtotal 1003, diskon sepuluh persen menghasilkan 902.7, dan
int(...) dibulatkan ke bawah menjadi 902. Perhatikan assert pertama juga: pada 200 pence dan empat
cangkir total tetap 803 — tes batas membuktikan bahwa diskon aktif
dan juga tidak aktif terlalu dini.
Contoh terpecahkan 2 (memotong dua bug dengan cetakan, ditingkatkan). Total dari 1.5
cetakan {'tea': 3} tetapi baris terlaris mencetak minuman yang salah. Metodenya:
(1) reproduksi dengan input gagal terkecil; (2) cetak nilai pada batas
antara bagian terpercaya dan bagian yang dicurigai — di sini, total sebelum max;
(3) perbaiki satu hal; (4) jalankan kembali tes. Memindahkan print di tengah-tengah kode
setiap menjalankan memotong separuh pencarian: empat cetakan menemukan bug dalam program sebelas belas baris, namun
seberapa pun ia bersembunyi.
Penyelarasan adalah menemukan perbedaan antara apa yang Anda yakini dilakukan kode
dan apa yang sebenarnya dilakukannya — cetakan pada batas percaya/curiga adalah alatnya.
Kesalahan umum. Menguji hanya jalur bahagia: batas-batas (nol, satu, kosong,
negatif) adalah tempat program rusak. Menulis minggu kode sebelum tes pertama,
lalu menyelaraskan gunung. Memperbaiki dua hal sekaligus, sehingga tidak ada hasil yang bermakna
sesuatu lainnya.
Ringkasan: dekomposisikan hingga setiap bagian diuji secara mandiri; nyatakan batas-batas segera setelah sebuah
fungsi ada; tulis tes terlebih dahulu jika memungkinkan; selaraskan dengan biseksi menggunakan cetakan
pada batas kepercayaan — kebiasaan yang menjadi fondasi seluruh gelar ini.
Pelajaran interaktif untuk topik ini
Kerjakan langkah demi langkah, dengan latihan pengecekan instan.