Mengenal Python
Kenapa Python, cara memasangnya, dan pilih editor.
Mengenal Python
- 01Pahami konsepnya · 3
- 02Coba contoh kode · 1
Kenapa Python, cara memasangnya, dan pilih editor.
Python diciptakan Guido van Rossum dan rilis pertamanya tahun 1991. Falsafahnya terkenal: kode harus terbaca seperti bahasa manusia — hampir tanpa kurung kurawal, tanpa titik koma wajib, blok ditandai indentasi. Hasilnya program Python sering terlihat seperti pseudocode yang tiba-tiba bisa dijalankan.
Python dipakai di mana-mana: ilmu data dan AI (pustaka NumPy, Pandas, PyTorch), otomasi dan skrip, web (Django, Flask, FastAPI), sampai pendidikan — ia bahasa pengantar informatika paling populer di universitas dunia. Kenapa? Karena kurva belajarnya landai: satu jam pertama sudah bisa menulis program berguna.
Untuk memasang: unduh installer dari python.org (pastikan centang "Add to PATH" di Windows) atau gunakan manajer paket (brew install python di Mac, apt install python3 di Linux). Verifikasi dengan python --version atau python3 --version di terminal. Editor yang populer: VS Code dengan ekstensi Python (gratiss, lintas platform), PyCharm (kaya fitur), atau bahkan IDLE yang sudah ikut dalam installer.
Perintah ini memastikan Python terpasang dan menunjukkan versinya. Di Windows biasanya cukup python --version (tanpa angka 3); di Mac dan Linux python3 adalah konvensi. Angka 3 penting — Python 2 sudah pensiun sejak 2020.
Cetak teks dengan print() dan tulis komentar.
Fungsi print() adalah pintu keluar paling dasar: print("Halo!") menampilkan teks lalu berpindah baris. Ia menerima beberapa argumen dipisah koma — print("umur:", 17) mencetak umur: 17 dengan spasi otomatis. Untuk cetak multi-baris, Python punya string tiga kutip: print("""baris satu\nbaris dua""") atau langsung kutip tiga berisi teks dengan baris-barisnya.
Komentar ditandai tanda pagar # — segala teks setelahnya diabaikan interpreter hingga akhir baris. Untuk blok panjang, Python tidak punya komentar blok khusus; pakai tiga kutip sebagai string "tak dipakai" atau beberapa baris #. Komentar yang baik menjelaskan KENAPA, bukan apa — sama seperti bahasa lain.
Program Python disimpan sebagai berkas .py dan dijalankan dengan python nama.py. Tidak ada tahap kompilasi terpisah — interpreter membaca dan mengeksekusi baris demi baris. Itulah kenanya Python disebut bahasa skrip: sunting, jalankan, lihat hasil.
Empat pola cetak sekaligus: teks tunggal, multi-argumen dengan spasi otomatis, dan blok multi-baris lewat tiga kutip. Komentar # tidak pernah tampil di keluaran. Simpan sebagai main.py lalu jalankan python main.py.
Uji: program harus mencetak persis `Halo, Python!` lalu `Siap belajar!`.
# Ini komentar — diabaikan oleh Python
print("Halo dari Python!")
print("umur:", 17, "tahun")
# String tiga kutip untuk multi-baris:
print("""
Baris pertama
Baris kedua
""")Tiga cara: REPL interaktif, berkas .py, dan VS Code.
Python bisa dijalankan tiga cara. Pertama, mode interaktif (REPL): ketik python di terminal dan kamu masuk prompt >>> — setiap baris langsung dieksekusi dan hasilnya ditampilkan. Sempurna untuk eksperimen cepat: coba 2 + 3, len("halo"), atau import math lalu math.pi. Keluar dengan exit() atau Ctrl+D.
Kedua, berkas skrip: simpan kode di berkas .py lalu jalankan python nama.py dari terminal. Ini cara normal untuk program sungguhan. Ketiga, lewat editor: VS Code dengan ekstensi Python memberikan tombol Run di editor, plus terminal terintegrasi, debugger, dan Intellisense — kombinasi yang membuat siklus sunting-jalankan sangat cepat.
Satu istilah penting: saat menjalankan berkas, Python membuat variabel khusus __name__. Jika berkas dijalankan langsung, nilainya "__main__"; jika diimpor sebagai modul, nilainya nama berkasnya. Konvensi if __name__ == "__main__": menandai kode yang hanya boleh berjalan saat eksekusi langsung — bukan saat diimpor.
Saat python main.py dijalankan, __name__ bernilai "__main__" sehingga blok if terpenuhi. Jika berkas ini diimpor (import main), blok itu dilewati — kode uji dan demo tidak mengotori pemakai. Pola ini standar di proyek Python nyata.
Simpan nilai tanpa deklarasi tipe, kenali int/float/str/bool.
Variabel Python lahir saat pertama diisi — cukup nama = nilai, tanpa kata kunci var/let, tanpa menyebut tipe. nama = "Ari" langsung menciptakan variabel bertipe string; umur = 17 menciptakan integer. Tipenya ditentukan nilai yang dipegang, dan bisa berganti kapan saja — Python bersifat dinamis.
Fungsi type() memeriksa tipe nilai: type(17) menghasilkan <class 'int'>, type(1.5) float, type("halo") str, type(True) bool. Angka dibagi int (bulat, tanpa batas ukuran) dan float (desimal 64-bit). Konversi dilakukan dengan nama tipe sebagai fungsi: int("42") teks ke angka, str(17) angka ke teks, float("3.14") teks ke desimal.
Membaca masukan pengguna: input("pertanyaan") selalu mengembalikan STRING — meski yang diketik angka. Berhitung dengannya perlu konversi eksplisit: umur = int(input("Umur: ")). Konstanta di Python hanya konvensi penamaan NAMA_KAPITAL — interpreter tidak menguncinya, tapi pembaca kode menghormatinya.
Perhatikan kontras penting: teks + "5" merangkai string ("425"), angka + 5 menjumlahkan integer (47). input() mengembalikan string sehingga int() wajib sebelum dihitung. f-string (f"...{umur + 1}") menyisipkan ekspresi langsung ke dalam teks — cara modern memformat di Python.
Uji: baca nama dan umur, tambah satu tahun, cetak `nama berumur X` — masukkan `Ari` dan `17`, harus `Ari berumur 18`.
nama = "Ari"
umur = 17
tinggi = 168.5
aktif = True
print(type(nama), type(umur), type(tinggi), type(aktif))
# konversi
teks = "42"
angka = int(teks)
print(teks + "5") # string: "425"
print(angka + 5) # int: 47
# input selalu string
masukan = input("Umur: ")
umur = int(masukan)
print(f"Tahun depan: {umur + 1}")Aritmetika, perbandingan, logika, dan assignment singkat.
Operator aritmetika Python: + - * / dan // untuk pembagian bulat (floor), % untuk sisa, ** untuk pangkat. Beda penting: / SELALU menghasilkan float (7 / 2 = 3.5) sedangkan // memotong ke bawah (7 // 2 = 3). Pangkat ditulis ** bukan ^ — tanda sisip punya arti lain di Python.
Perbandingan menghasilkan bool: == != < > <= >=. Operator `is` membandingkan identitas objek (apakah variabel yang sama di memori), bukan nilainya — hati-hati memakainya untuk angka/string karena hasilnya bisa tak terduga. Logika: and, or, not — kata Inggris, bukan simbol && || !.
Penugasan singkat: += -= *= /= //= %= **= — semua pola var = var op nilai diringkas. Python juga mendukung penugasan berantai (a = b = 0) dan penugasan paralel (x, y = 1, 2) yang akan dibahas dalam di pack-unpack.
Pembagian / vs // adalah jebakan klasik: 7/2 menghasilkan 3.5 (float) sedangkan 7//2 menghasilkan 3 (int). Operator ** untuk pangkat, and/or/not untuk logika — semuanya kata Inggris, bukan simbol.
Uji: cetak hasil 7/2, 7//2, 7%2, 7**2 — harus `3.5`, `3`, `1`, `49`.
a, b = 7, 2
print(a / b) # 3.5 — selalu float
print(a // b) # 3 — dibulatkan ke bawah
print(a % b) # 1 — sisa
print(a ** b) # 49 — pangkat
print(a > b and b > 0) # True
print(not a > b) # False
counter = 10
counter += 5 # 15
counter **= 2 # 225Bercabang lewat if, elif, else — blok ditandai indentasi.
Struktur kondisional Python unik: TIDAK ADA kurung kurawal. Blok ditandai indentasi (biasanya 4 spasi) setelah titik dua. if nilai >= 90: lalu baris berikutnya menjorok — semua baris sejajar itu isi blok. elif menggantikan else if, dan else menampung sisanya.
Python juga punya operator ternary versi elegan: "lulus" if nilai >= 70 else "remedial" — kondisi di tengah, hasil benar di kiri, hasil salah di kanan. Dan fitur unik: chaining perbandingan seperti matematika: 0 <= nilai <= 100 berarti nilai >= 0 AND nilai <= 100 sekaligus.
Kesalahan umum: lupa titik dua, atau indentasi campur spasi-tab (Python 3 menolak tab). Gunakan 4 spasi konsisten — editor modern mengurusnya otomatis.
Perhatikan titik dua di tiap cabang dan indentasi 4 spasi di bawahnya — tanpa keduanya Python menolak. Ternary membaca "lulus JIKA nilai>=70 SELAIN ITU remedial". Chaining 13 <= umur <= 19 menggantikan dua perbandingan dengan and.
Uji: nilai 82 harus `B`; ganti ke 65 dan harus `D`.
nilai = 82
if nilai >= 90:
print("A")
elif nilai >= 80:
print("B")
elif nilai >= 70:
print("C")
else:
print("D")
# ternary
status = "lulus" if nilai >= 70 else "remedial"
print(status)
# chaining
umur = 25
print(13 <= umur <= 19) # False — bukan remajaUlangi sejumlah kali dengan range() atau susuri koleksi.
Perulangan for Python berbeda dari C/Go: ia selalu menyusuri koleksi (iterable). for i in range(5): berputar lima kali dengan i bernilai 0,1,2,3,4 — range(n) menghasilkan 0 sampai n-1. range(1, 11) mulai 1 sampai 10; range(0, 101, 5) melompat lima-lima: 0, 5, 10, ... 100.
For bisa langsung menyusuri koleksi tanpa indeks: for nama in ["andi", "budi", "citra"]: memberi tiap elemen. Bila indeks DAN elemen sama-sama dibutuhkan, gunakan enumerate(): for i, nama in enumerate(daftar): memberi keduanya sekaligus.
Fitur unik Python: for-else. Blok else setelah for hanya berjalan bila loop selesai NORMAL (tanpa break) — pas untuk pencarian: break saat ketemu, else cetak "tidak ditemukan" bila putus tanpa ketemu.
end=" " pada print mengganti baris-baru bawaan dengan spasi sehingga keluaran menyatu satu baris. range(10, 0, -2) menghitung MUNDUR dari 10 dengan langkah -2. for-else adalah tameng pencarian: else hanya jalan bila tidak ada break.
Uji: cetak `7 x 1 = 7` sampai `7 x 10 = 70`.
# range dasar
for i in range(5):
print(i, end=" ") # 0 1 2 3 4
print()
# range dengan awal, akhir, langkah
for n in range(10, 0, -2):
print(n, end=" ") # 10 8 6 4 2
print()
# enumerate: indeks + elemen
buah = ["apel", "mangga", "jeruk"]
for i, nama in enumerate(buah):
print(f"{i}: {nama}")
# for-else
target = 7
for n in range(10):
if n == target:
print(f"ketemu: {n}")
break
else:
print("tidak ditemukan")Ulangi selama syarat benar; break keluar, continue lompat.
while mengulang selama syaratnya True — untuk jumlah putaran yang belum diketahui di depan. while True: membuat loop tak hingga yang dijaga break — pola standar untuk menu, baca-input-sampai-selesai, dan game loop.
break keluar dari loop seketika. continue melewati sisa putaran saat itu dan langsung melompat ke putaran berikutnya. Python punya pass — pernyataan "tidak melakukan apa pun" — berguna sebagai placeholder saat merancang kerangka kode.
Jebakan klasik: lupa memajukan variabel syarat di dalam loop, sehingga while tidak pernah menjadi False dan program berputar selamanya. Selalu pastikan ada jalan keluar — variabel penghitung yang bertambah, atau break yang pasti terpicu.
Loop while True dijaga break saat pengguna mengetik 0. Continue pada loop kedua melompati ganjil sehingga hanya genap tercetak. Pola while True + break adalah bentuk paling alami membaca input sampai tanda selesai.
Uji: hitung digit dari 4050 (bagi 10 terus) — masukkan `4050`, harus `4`.
# baca angka sampai 0
total = 0
while True:
teks = input("Angka (0=berhenti): ")
n = int(teks)
if n == 0:
break
total += n
print(f"Total: {total}")
# continue: lewati bilangan ganjil
for i in range(10):
if i % 2 == 1:
continue
print(i, end=" ") # 0 2 4 6 8Indeks, method umum, escape sequence, dan iterasi karakter.
String Python adalah sequence karakter: bisa diindeks s[0], dislice s[1:4], disusuri for c in s. String TIDAK BISA diubah (immutable) — s[0] = "x" error; operasi "mengubah" string selalu menghasilkan string baru.
Method penting: len(s) panjang, s.upper() / s.lower() kapital, s.strip() pangkas spasi dua sisi, s.split(",") pecah jadi list, "-".join(list) gabung, s.replace("lama", "baru") ganti, s.find("sub") posisi atau -1, s.startswith("pre") / s.endswith(".txt") cek awal-akhir, s.count("a") hitung kemunculan.
Escape sequence: \n baris baru, \t tab, \\ backslash, \" kutip ganda dalam string kutip ganda. String mentah r"..." mematikan escape — r"C:\folder\baru" tetap berisi backslash literal.
strip() memangkas spasi betis; split() memecah jadi list; replace menghasilkan string BARU (asli tak berubah). String mentah r"..." penting untuk path Windows dan regex — backslash tidak ditafsirkan.
Uji: hitung kata dan ganti `seru`→`mantap` — harus `4` lalu `Belajar Python itu mantap`.
s = " Belajar Python itu seru "
bersih = s.strip()
print(len(bersih))
print(bersih.upper())
print(bersih.split(" "))
print(bersih.replace("seru", "mantap"))
print(bersih.startswith("Belajar"))
# iterasi karakter
for c in "halo":
print(c, end="-") # h-a-l-o-
print()
# string mentah
print(r"C:\folder\baru") # backslash tetap utuhf-string, format(), join(), dan align.
f-string adalah cara modern (Python 3.6+): f"Halo {nama}, umur {umur}" menyisipkan variabel langsung dalam kurung kurawal. Ekspresi juga bisa: f"{harga * jumlah:,}" menghasilkan angka dengan pemisah ribuan. Format spesifik: {x:.2f} dua desimal, {x:>10} rata kanan lebar 10, {x:<10} rata kiri, {x:^10} tengah.
Metode .format() adalah pendahulu: "Halo {}".format(nama) — masih berguna bila teks disimpan sebagai template variabel. join() adalah kebalikan split(): ", ".join(["a", "b", "c"]) menghasilkan "a, b, c" — cara paling cepat merangkai list jadi string (lebih cepat dari + berulang).
Untuk debug cepat: f"{variabel=}" (Python 3.8+) mencetak nama dan isinya sekaligus — f"{harga=}" menghasilkan harga=25000.
f-string dengan :.1f membulatkan tampilan satu desimal; > < ^ mengatur perataan dalam lebar tetap; :, menambah pemisah ribuan. join jauh lebih efisien daripada perulangan + untuk merangkai list.
Uji: satu f-string menghasilkan `Ari | 17 | Rp1.250.000` (align 4, umur, harga ribuan).
nama, umur, tinggi = "Ari", 17, 168.5
# f-string dengan format
print(f"Nama: {nama}, umur: {umur}, tinggi: {tinggi:.1f} cm")
# align
print(f"{nama:>10} |")
print(f"{nama:<10} |")
print(f"{nama:^10} |")
# ribuan
harga = 1234567
print(f"Rp{harga:,}")
# join
buah = ["apel", "mangga", "jeruk"]
print(", ".join(buah))
# debug cepat
print(f"{harga=}")Daftar terurut yang bisa berubah — koleksi paling sering dipakai.
List adalah daftar terurit yang isinya bisa ditambah, dihapus, dan diganti: daftar = [1, 2, 3]. Indeks mulai nol: daftar[0] adalah 1. List bisa berisi tipe campuran — [1, "halo", True] sah — dan bisa bersarang: matriks = [[1,2], [3,4]].
Method penting: append(x) menambah di akhir, insert(i, x) di posisi, remove(x) lepas nilai pertama yang cocok, pop() ambil- hapus terakhir, sort() urutkan di tempat, reverse() balik. len() menghitung jumlah, in menguji keanggotaan: 3 in [1,2,3] adalah True.
List adalah REFERENCE — variabel menunjuk memori yang sama. b = a tidak menyalin; ubah b dan a ikut berubah. Untuk salinan asli: b = a.copy() atau b = list(a). del daftar[0] menghapus indeks; del daftar menghapus seluruh variabel dari memori.
Jebakan reference: b = a lalu b.append(4) — a ikut berubah karena keduanya menunjuk memori yang sama. copy() membuat salinan terpisah. Pola ini penting di semua bahasa ber-reference.
Uji: buat [5,3,8,1,9], urutkan, cetak — harus `[1, 3, 5, 8, 9]`.
buah = ["apel", "mangga", "jeruk"]
buah.append("pisang")
buah.insert(1, "anggur")
buah.remove("jeruk")
print(buah)
print(len(buah), "apel" in buah)
# reference vs copy
a = [1, 2, 3]
b = a # reference — bukan salinan
b.append(4)
print(a) # [1, 2, 3, 4] — a ikut berubah!
c = a.copy() # salinan asli
c.append(5)
print(a) # [1, 2, 3, 4] — a amanBangun list satu baris: [ekspresi for x in iterable if syarat].
List comprehension adalah sintaks ringkas Python untuk membangun list dari iterable. Bentuk dasar: [x * 2 for x in range(5)] menghasilkan [0, 2, 4, 6, 8]. Dengan filter: [x for x in range(20) if x % 3 == 0] memberi kelipatan 3. Bentuknya membaca seperti matematika — "x pangkat dua UNTUK x DI range(5) JIKA x genap".
Kuasainya bukan gaya-gayaan: comprehension LEBIH CEPAT daripada loop + append (Python mengoptimalkannya secara internal) dan lebih ringkas. Bila logikanya muat satu baris yang terbaca jelas, comprehension menang; bila butuh tiga baris atau ada side-effect, loop biasa lebih jernih.
Versi untuk struktur lain juga ada: {x**2 for x in range(5)} (set comprehension) dan {k: v for k, v in data} (dict comprehension). Prinsip sama, kurung berbeda.
Tiga bentuk sekaligus: transformasi murni (x**2), dengan filter (if genap), dan pada string. Set comprehension otomatis menghilangkan duplikat — x % 3 dari 0..9 hanya menghasilkan {0, 1, 2}.
Uji: kuadrat dari 1-5 yang genap — harus `[4, 16]`.
# dasar
kuadrat = [x**2 for x in range(1, 6)]
print(kuadrat) # [1, 4, 9, 16, 25]
# dengan filter
genap = [x for x in range(20) if x % 2 == 0]
print(genap)
# transformasi string
nama = ["andi", "budi", "citra"]
kapital = [n.upper() for n in nama]
print(kapital)
# set comprehension
unik = {x % 3 for x in range(10)}
print(unik) # {0, 1, 2}Ambil bagian sequence: [start:stop:step].
Slice mengambil bagian dari string, list, atau tuple lewat tiga angka: [start:stop:step]. start adalah indeks awal (ikut), stop indeks akhir (TIDAK ikut), step lompatan. angka[2:5] mengambil indeks 2-4; angka[::2] mengambil tiap kedua; angka[::-1] MENGBALIK urutan.
Yang dihilangkan otomatis diisi: [:3] dari awal sampai indeks 2; [3:] dari indeks 3 sampai akhir; [:] salinan penuh. Indeks negatif berhitung dari belakang: [-1] elemen terakhir, [-3:] tiga terakhir.
Slice menghasilkan objek BARU (bukan reference ke asli) — mengubah hasil slice tidak menyentuh sumbernya. Ini beda penting dari assignment biasa pada list.
Slice [::-1] adalah idiom Python untuk membalik urutan — berlaku untuk string, list, dan tuple. [::2] mengambil elemen berindeks genap (0, 2, 4, 6). Indeks negatif [-3:] memberi tiga elemen terakhir.
Uji: tiga karakter tengah dari `Python` (indeks 1-3) — harus `yth`.
huruf = ["a", "b", "c", "d", "e", "f", "g"]
print(huruf[2:5]) # ["c", "d", "e"]
print(huruf[:3]) # ["a", "b", "c"]
print(huruf[4:]) # ["e", "f", "g"]
print(huruf[::2]) # ["a", "c", "e", "g"]
print(huruf[::-1]) # ["g", "f", "e", "d", "c", "b", "a"]
print(huruf[-3:]) # ["e", "f", "g"]
# slice pada string
s = "Belajar Python"
print(s[0:7]) # Belajar
print(s[::-1]) # nohtyP rajaleBSekuens tetap yang tidak bisa diubah setelah dibuat.
Tuple adalah list yang TIDAK BISA diubah (immutable): koordinat = (3, 7). Setelah dibuat, isinya terkunci — tidak ada append, remove, atau assignment indeks. Kekurangan itu justru kelebihannya: tuple aman dari modifikasi tak sengaja, bisa jadi kunci dictionary (list tidak bisa), dan lebih hemat memori.
Deklarasi dengan kurung: t = (1, 2, 3) atau tanpa kurung t = 1, 2, 3. Tuple satu elemen WAJIB koma: t = (5,) — tanpa koma itu bukan tuple, hanya bilangan dalam kurung. Tuple bisa di-unpack: x, y = koordinat memberi x=3, y=7.
Fungsi Python sering mengembalikan tuple: divmod(17, 5) memberi (3, 2). Method-nya hanya dua: count(x) dan index(x) — karena isinya memang tak bisa diubah.
Unpacking adalah fitur bintang tuple: x, y = koordinat membongkar isinya langsung ke dua variabel. divmod() mengembalikan tuple (hasil bagi, sisa). Tuple bisa jadi kunci dictionary karena isinya tetap — list yang bisa berubah tidak boleh.
Uji: tukar a=10, b=20 via unpack — harus `20 10`.
koordinat = (3, 7)
x, y = koordinat
print(f"x={x}, y={y}")
# swap tanpa variabel bantu
a, b = 1, 2
a, b = b, a
print(a, b) # 2 1
# tuple dari fungsi
hasil = divmod(17, 5) # (bagi, sisa)
print(f"17 bagi 5 = {hasil[0]} sisa {hasil[1]}")
# tuple sebagai kunci dict (list tidak bisa)
harga = {(3, 7): "mahal", (1, 2): "murah"}
print(harga[(3, 7)]) # mahalKoleksi unik tanpa urutan dengan operasi himpunan.
Set adalah koleksi yang otomatis menghilangkan duplikat: set([1, 2, 2, 3, 3, 3]) menjadi {1, 2, 3}. Tanpa indeks (karena tidak terurut), tidak bisa di-slice, tapi punya operasi himpunan yang powerful: union | , intersection & , difference - , symmetric difference ^.
Deklarasi dengan kurung kurawal: s = {1, 2, 3} atau set() untuk kosong ({} kosong membuat dict!). add() menambah, remove/discard menghapus (remove error bila tidak ada, discard diam). in sangat cepat pada set — O(1) dibanding O(n) pada list.
Use case klasik: menghilangkan duplikat dari list (list(set(daftar))), menguji keanggotaan cepat, dan operasi himpunan seperti "angka yang ada di A tapi tidak di B" — satu baris: a - b.
Empat operasi himpunan dalam empat baris: | gabungan, & irisan, - selisih, ^ simetris. list(set(data)) adalah idiom satu baris untuk menghilangkan duplikat dari list.
Uji: irisan {1,2,3,4} dan {3,4,5,6} — harus `{3, 4}`.
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}
print(a | b) # union: semua
print(a & b) # intersection: sama
print(a - b) # difference: di A saja
print(a ^ b) # symmetric: bukan keduanya
# deduplikasi
data = [1, 2, 2, 3, 3, 3, 4]
unik = list(set(data))
print(unik) # [1, 2, 3, 4]
# keanggotaan cepat
print(3 in a) # TruePasangan kunci-nilai yang dicari berdasarkan nama, bukan posisi.
Dictionary memetakan kunci ke nilai: stok = {"kopi": 12, "teh": 8}. Akses, tambah, dan ubah lewat kurung siku: stok["kopi"], stok["susu"] = 5 (tambah baru), stok["teh"] += 2. Kunci harus tipe hashable — string, angka, tuple — tidak bisa list.
Method penting: get(kunci, cadangan) mengembalikan nilai atau cadangan tanpa error (stok.get("matcha", 0) memberi 0), keys() / values() / items() untuk iterasi, pop(k) hapus- ambil, update(dict) gabung. Python 3.9+ punya operator merge: {**a, **b} atau a | b menggabung dua dict.
Iterasi dengan items() memberi kunci dan nilai sekaligus: for produk, jumlah in stok.items():. Urutan dict dijamin mengikuti urutan penyisipan sejak Python 3.7.
get() dengan cadangan menghindari KeyError saat kunci tidak ada — pola penting untuk data opsional. items() memberi kunci dan nilai sekaligus tanpa perlu indeks. Operator | menggabung dict dalam satu ekspresi bersih.
Uji: kurangi kopi dari 2 ke 0 lalu HAPUS — harus `{"teh": 8}`.
stok = {"kopi": 12, "teh": 8}
stok["susu"] = 5
stok["teh"] += 2
# get dengan cadangan
print(stok.get("matcha", 0)) # 0 — tanpa error
# iterasi kunci-nilai
for produk, jumlah in stok.items():
print(f"{produk}: {jumlah}")
# merge (Python 3.9+)
harga = {"kopi": 18000, "teh": 8000}
gabung = stok | {"diskon": True}
print(gabung)
# hapus
stok.pop("teh")
print("teh" in stok) # FalseBongkar koleksi ke variabel dan kemas kembali dengan *.
Unpack bongkar koleksi ke variabel: a, b, c = [1, 2, 3] memberi tiga variabel terpisah. Tuple swap a, b = b, a adalah aplikasi tersohornya. Jumlah variabel HARUS sama dengan jumlah elemen — kecuali memakai * untuk menangkap sisanya: first, *rest = [1, 2, 3, 4] memberi first=1, rest=[2, 3, 4].
Pack adalah kebalikannya: * memecah koleksi jadi argumen terpisah. print(*[1, 2, 3]) sama dengan print(1, 2, 3). Pada pemanggilan fungsi: fungsi(*daftar) membongkar daftar jadi argumen posisional; fungsi(**dict) membongkar dict jadi argumen kata kunci.
Dict juga bisa di-unpack: a, b = mydict membongkar KUNCINYA (bukan nilainya). Untuk nilai, gunakan .values() atau .items() — for k, v in d.items() adalah unpack di dalam loop.
Star di sisi KIRI (first, *rest) menangkap sisa elemen saat unpack. Star di sisi KANAN (*angka) memecah koleksi jadi argumen terpisah saat pemanggilan. Dua arah star ini adalah fondasi *args/**kwargs di pelajaran fungsi.
Uji: bongkar (10,20,30,40) jadi first, *rest — harus `10 [20, 30, 40]`.
# unpack dasar
a, b, c = 1, 2, 3
print(a, b, c) # 1 2 3
# star menangkap sisanya
first, *tengah, last = [1, 2, 3, 4, 5]
print(first, tengah, last) # 1 [2, 3, 4] 5
# pack: splat ke fungsi
angka = [10, 20, 30]
print(*angka) # 10 20 30
# unpack dict
data = {"nama": "Ari", "umur": 17}
for k, v in data.items():
print(f"{k} = {v}")Kemas langkah bernama, kembalikan hasil, dan panggil diri sendiri.
Fungsi dideklarasikan dengan def nama(param): lalu blok berindentasi. return mengirim hasil ke pemanggil dan segera menghentikan fungsi; tanpa return, Python mengembalikan None. Fungsi bisa mengembalikan beberapa nilai sekaligus sebagai tuple: return min, max.
Rekursi adalah fungsi yang memanggil dirinya sendiri untuk versi lebih kecil dari masalahnya. Kasus klasik faktorial: faktorial(5) = 5 * faktorial(4) = ... = 5*4*3*2*1. Syarat wajib: KASUS DASAR yang menghentikan pemanggilan — faktorial(1) = 1 — tanpanya rekursi berputar selamanya.
Docstring adalah string tiga-kutip pertama dalam fungsi — dokumentasi resmi Python: help(nama_fungsi) membacanya. Konvensi singkat menjelaskan apa, parameter, dan nilai balik.
diskon mengembalikan satu nilai; faktorial memanggil dirinya sendiri dengan n-1 sampai kasus dasar n<=1 menghentikannya. help() membaca docstring dan menampilkannya sebagai dokumentasi.
Uji: fib(6) rekursif — harus `8`.
def diskon(harga, persen):
"""Hitung nilai diskon dari harga."""
return harga * persen / 100
def faktorial(n):
if n <= 1:
return 1
return n * faktorial(n - 1)
print(diskon(100000, 20))
print(faktorial(5))
print(help(diskon))Nilai bawaan, jumlah bebas posisional, dan kata kunci.
Parameter boleh punya nilai bawaan: def sapa(nama, sapaan="Halo"): — pemanggil cukup kirim nama; sapaan boleh dilewati, diganti, atau dikirim dengan nama: sapa("Ari", sapaan="Selamat"). Argumen posisional dikirim berurutan; keyword argument dikirim dengan nama sehingga urutan bebas.
*args mengumpulkan argumen posisional berlebih menjadi tuple: def jumlah(*angka): menerima jumlah berapa pun — jumlah(1, 2, 3) memberi angka = (1, 2, 3). **kwargs mengumpulkan keyword argument berlebih menjadi dict: def profil(**data): menerima nama="Ari", umur=17 sebagai data = {"nama": "Ari", "umur": 17}.
Urutan deklarasi wajib: parameter biasa, *args, parameter keyword-only, **kwargs. Star di definisi mengumpulkan; star di pemanggilan memecah — dua sisi koin yang sama.
sapa menunjukkan tiga cara memanggil: posisional saja, campuran, dan semua keyword. *args mengubah lima angka menjadi tuple yang diiterasi; **kwargs mengubah tiga pasangan menjadi dict yang di-loop items().
Uji: rata(*angka) — rata(10,20,30) harus `20.0`.
def sapa(nama, sapaan="Halo"):
return f"{sapaan}, {nama}!"
print(sapa("Ari"))
print(sapa("Budi", "Selamat pagi"))
print(sapa(nama="Citra", sapaan="Oi"))
def jumlah(*angka):
total = 0
for n in angka:
total += n
return total
print(jumlah(1, 2, 3, 4, 5)) # 15
def profil(**data):
for k, v in data.items():
print(f" {k}: {v}")
profil(nama="Ari", umur=17, kota="Bandung")Fungsi anonim satu-baris dan operasi koleksi fungsional.
Lambda adalah fungsi anonim satu ekspresi: kali_dua = lambda x: x * 2. Ia setara fungsi def singkat tapi tanpa nama dan tanpa多 baris. Kegunaan utamanya: dikirim sebagai argumen ke fungsi lain yang mengharapkan fungsi — sort(key=lambda x: x[1]), map(lambda x: x*2, data).
map(fungsi, iterable) menerapkan fungsi ke tiap elemen dan mengembalikan iterator: list(map(str.upper, nama)). filter(fungsi, iterable) menyaring elemen yang membuat fungsi True: list(filter(lambda x: x > 5, angka)). Keduanya mengembalikan iterator — konversi list() untuk melihat hasilnya.
reduce dari functools menggabungkan elemen menjadi satu nilai: reduce(lambda a, b: a + b, angka) menjumlahkan seluruh list. Versi Pythonic-nya sering comprehension: [x*2 for x in data] menggantikan map, [x for x in data if x > 5] menggantikan filter.
Lambda paling bersinar sebagai key untuk sort — satu baris mengurutkan berdasarkan elemen kedua tuple. map dan filter mengembalikan iterator; list() mengubahnya untuk dicetak. Dua baris terakhir menunjukkan comprehension yang setara — gaya yang lebih Pythonic.
Uji: filter kelipatan 3 dari 1-20 — harus `[3, 6, 9, 12, 15, 18]`.
angka = [3, 8, 1, 9, 4, 6]
# lambda + sort
pasangan = [("andi", 85), ("budi", 92), ("citra", 78)]
pasangan.sort(key=lambda p: p[1], reverse=True)
print(pasangan)
# map
dobel = list(map(lambda x: x * 2, angka))
print(dobel)
# filter
besar = list(filter(lambda x: x > 5, angka))
print(besar)
# comprehension setara
print([x * 2 for x in angka])
print([x for x in angka if x > 5])Bedakan variabel dalam fungsi dan di luarnya.
Variabel yang dideklarasikan di dalam fungsi bersifat LOCAL — hanya hidup di dalamnya. Variabel di level modul bersifat GLOBAL — terlihat dari mana saja. Python mencari nama dari dalam ke luar: fungsi melihat global, tapi fungsi TIDAK BISA mengubah global tanpa izin.
Untuk mengubah variabel global dari dalam fungsi, nyatakan global nama_variabel di awal fungsi. Tanpanya, assignment di dalam fungsi menciptakan variabel LOCAL baru yang menimpa nama global secara lokal saja.
Kebiasaan terbaik: batasi global seminimal mungkin — ia membuat alur data sulit dilacak. Kirim data lewat parameter, terima hasil lewat return. global hanya untuk konfigurasi benar-benar lintas fungsi seperti penghitung debug.
tambah_local mengubah variabel local-nya sendiri bernama sama — global tetap 0. tambah_global dengan global counter benar-benar menaikkan variabel global. Tanpa global, Python menciptakan salinan local yang menimpa nama global secara lokal.
Uji: naikkan counter global dari 5 ke 6 — harus `6`.
counter = 0 # global
def tambah_local():
counter = 100 # local — global tidak tersentuh
def tambah_global():
global counter
counter += 1
tambah_local()
print(counter) # 0 — tidak berubah
tambah_global()
tambah_global()
print(counter) # 2 — global diubahImport modul, gunakan math/random, pahami __name__.
Modul adalah berkas Python yang bisa diimpor ke berkas lain: import math membawa seluruh modul, from math import pi membawa bagian spesifik, import numpy as np memberi nama pendek. Pilihan bentuknya sesuai selera dan kejelasan.
Standard library Python sangat kaya: math (sqrt, pi, floor), random (randint, choice, shuffle), datetime (now, strftime), os (listdir, path), json, csv, re, collections. Tanpa instalasi apa pun — semua sudah ikut Python.
Variabel __name__ menjadi "__main__" saat berkas dijalankan langsung, atau nama modul saat diimpor. Konvensi if __name__ == "__main__": menjaga kode demo/uji agar hanya berjalan saat eksekusi langsung, tidak saat diimpor oleh berkas lain.
math menyediakan sqrt dan pi; random menyediakan dadu (randint 1-6) dan pilihan acak (choice). Blok if __name__ hanya aktif saat berkas ini dieksekusi langsung — import math dari berkas lain tidak memicunya.
Uji: lempar 2 dadu 10x, hitung total 7 — harus 10 baris `lempar N: total X` + 1 baris `total 7 muncul K kali`.
import math
import random
print(math.sqrt(144))
print(math.pi)
print(random.randint(1, 6))
print(random.choice(["kung", "pao", "chili"]))
# if __name__ == "__main__"
if __name__ == "__main__":
print("Dijalankan langsung — bukan diimpor.")Kelola dependensi eksternal dengan pip dan venv.
Pip adalah manajer paket Python: pip install requests mengunduh dan memasang pustaka eksternal. Pencarian di pypi.org — gudang ratusan ribu paket. pip list menampilkan yang terpasang, pip uninstall melepasnya.
Masalah klasik: proyek A butuh requests versi 2.28, proyek B butuh 2.31 — bentrok bila keduanya berbagi satu Python. Solusinya virtual environment: python -m venv nama-env menciptakan folder berisi Python terisolasi. Aktifkan dengan source nama-env/bin/activate (Mac/Linux) atau nama-env\Scripts\activate (Windows), lalu pip install bebas dari bentrok.
Packages adalah cara mengorganisir modul: folder berisi berkas __init__.py menjadi paket yang bisa diimpor per level: from paketku.modul import fungsi. Struktur proyek nyata: paket/modul.py, paket/__init__.py, main.py di luar.
Empat langkah venv: buat, aktifkan (prompt berubah), pasang paket, matikan. pip freeze > requirements.txt membekukan daftar dependensi agar proyek bisa dipasang ulang di komputer lain dengan pip install -r requirements.txt.
Baca waktu saat ini, format, dan parsing tanggal.
Modul datetime menyediakan kelas date (tanggal), time (jam), datetime (gabungan), dan timedelta (durasi). datetime.now() memberi waktu saat ini lengkap dengan mikrodetik; date.today() hanya tanggal. Selisih dua datetime menghasilkan timedelta: (besok - hari_ini).days memberi 1.
Format mengikuti kode persen: %Y tahun 4 digit, %m bulan 02, %d hari, %H jam, %M menit, %S detik. now.strftime("%d/%m/%Y %H:%M") menghasilkan bentuk yang kamu tulis polanya. Parsing adalah arah sebaliknya: datetime.strptime("15/03/2007", "%d/%m/%Y") membaca teks jadi objek datetime.
Timezone: Python 3.9+ punya ZoneInfo("Asia/Jakarta") untuk zona waktu bernama. Selama tanpa timezone, datetime bersifat naive (tanpa zona) — hati-hati membandingkan waktu lintas zona.
strftime mengubah datetime menjadi teks sesuai pola persen; strptime adalah arah sebaliknya — teks jadi objek datetime. timedelta memungkinkan aritmetika tanggal: tambah hari, kurang minggu.
Uji: parse `15/03/2007` lalu cetak tahun — harus `2007`.
from datetime import datetime, date, timedelta
sekarang = datetime.now()
print(sekarang)
print(sekarang.strftime("%d/%m/%Y %H:%M"))
# parsing
ulang = datetime.strptime("15/03/2007", "%d/%m/%Y")
print(f"Tahun lahir: {ulang.year}")
# timedelta
besok = date.today() + timedelta(days=1)
print(f"Besok: {besok}")Definisikan cetakan, buat objek, isi data lewat __init__.
Class adalah cetakan; objek adalah hasil cetaknya. class Siswa: mendefinisikan cetakan; ari = Siswa() mencetak satu objek. Method __init__(self, ...) adalah constructor — kode yang otomatis berjalan setiap objek dibuat, tempat mengisi atribut awal.
self adalah referensi ke objek itu sendiri — wajib parameter pertama tiap method. ari.nama = "Ari" bisa dari luar, tapi mengisinya di __init__ lebih rapi: semua atribut terdaftar di satu tempat.
Visibility Python pakai konvensi underscore: _nama "sebaiknya jangan disentuh" (protected), __nama "jangan sentuh" (private — Python mengganti namanya jadi _ClassName__nama). Tidak ada enforcement sungguhan seperti private Java — hanya kesepakatan komunitas.
Dua objek dari cetakan yang sama dengan data berbeda. __init__ menerima nama dan poin lalu menyimpannya sebagai atribut self. Method info mengakses atribut lewat self.
Uji: Siswa("Ari", 17).info() harus `Ari (17 poin)`.
class Siswa:
def __init__(self, nama, poin):
self.nama = nama
self.poin = poin
def info(self):
return f"{self.nama} ({self.poin} poin)"
ari = Siswa("Ari", 10)
budi = Siswa("Budi", 25)
print(ari.info())
print(budi.info())Fungsi yang menempel pada objek dan mengakses datanya.
Instance method adalah fungsi yang dideklarasikan di dalam class dan dipanggil dari objek: ari.tambah(25). Parameter pertamanya selalu self — referensi ke objek pemanggil. Di dalam method, atribut diakses lewat self.nama.
Method bisa memanggil method lain lewat self: self.hitung() di dalam method yang sama class. Boleh juga menerima parameter tambahan biasa: def bandingkan(self, lain): menerima objek lain sebagai argumen.
Python membolehkan menambah method setelah class selesai (monkey patching) tapi itu dianggap praktik buruk untuk kode produksi — definisikan semua method di dalam class.
Method tambah dan kurang MENGUBAH state objek lewat self; lulus hanya MEMBACA state. Pemanggilannya terbaca seperti kalimat: ari.tambah(50) — "ari, tambah 50".
Uji: bandingkan(self, lain) mengembalikan nama poin tertinggi — Ari 50 vs Budi 75, harus `Budi`.
class Siswa:
def __init__(self, nama, poin=0):
self.nama = nama
self.poin = poin
def tambah(self, n):
self.poin += n
def kurang(self, n):
self.poin -= n
def lulus(self):
return self.poin >= 70
ari = Siswa("Ari")
ari.tambah(50)
ari.tambah(25)
print(ari.poin, ari.lulus()) # 75 TrueData dan fungsi milik class, bukan objek individual.
Class attribute dibagikan semua objek: class Siswa: jumlah = 0 — setiap objek melihat nilai yang sama. Instance attribute (self.nama) milik objek masing-masing. Perbedaan penting: mengubah ClassNama.jumlah mengubah untuk semua; mengubah self.jumlah menciptakan salinan local untuk objek itu.
@classmethod menerima cls (class itu sendiri) alih-alih self — berguna untuk alternative constructor: from_string("Ari,17") membuat objek dari teks. @staticmethod tidak menerima self/cls sama sekali — fungsi biasa yang kebetulan tinggal di class, cocok untuk utilitas.
Urutan pencarian: Python mencari atribut di instance dulu, lalu class, lalu parent class. Karena itu objek bisa menimpa class attribute tanpa mengganggu yang lain.
Class attribute jumlah bertambah tiap __init__ berjalan — penghitung objek yang elegan. @classmethod dari_string adalah alternative constructor dari teks. @staticmethod valid tidak butuh self — fungsi utilitas murni.
Uji: class counter — 3 objek, cetak Siswa.jumlah, harus `3`.
class Siswa:
jumlah = 0 # class attribute — dibagi semua
def __init__(self, nama):
self.nama = nama
Siswa.jumlah += 1
@classmethod
def dari_string(cls, teks):
nama = teks.split(",")[0]
return cls(nama)
@staticmethod
def valid(nama):
return len(nama) >= 2
ari = Siswa("Ari")
budi = Siswa("Budi")
citra = Siswa.dari_string("Citra,17")
print(Siswa.jumlah) # 3
print(Siswa.valid("A")) # FalsePewarisan atribut dan method dari class induk.
Inheritance membuat class baru berdasarkan class lama: class Admin(Pengguna): — Admin mewarisi semua atribut dan method Pengguna, lalu menambahkan atau mengubah sesuai kebutuhan. Class induk disebut parent; class anak disebut child.
super() adalah jalan ke induk: super().__init__(...) memanggil constructor induk sebelum menambah inisialisasi sendiri. Method induk bisa dioverride — dideklarasikan ulang di anak dengan nama sama untuk perilaku berbeda.
Python mendukung multiple inheritance: class C(A, B) mewarisi dua induk. Method Resolution Order (MRO) menentukan urutan pencarian — biasanya left-to-right. Diamond problem (A→B,C→A) diselesaikan MRO C3 linearization.
Admin mewarisi Pengguna: constructor memanggil super().__init__ untuk bagian induk lalu menambah level. Method info dioverride untuk menampilkan prefix [Admin] sambil memanfaatkan super().info() untuk bagian induk.
Uji: Pelanggan(Pengguna) dengan saldo — info() harus `[Pelanggan] Budi <b@mail> saldo=50000`.
class Pengguna:
def __init__(self, nama, email):
self.nama = nama
self.email = email
def info(self):
return f"{self.nama} <{self.email}>"
class Admin(Pengguna):
def __init__(self, nama, email, level):
super().__init__(nama, email)
self.level = level
def info(self): # override
return f"[Admin L{self.level}] {super().info()}"
admin = Admin("Zaky", "ops@site.dev", 5)
print(admin.info()) # [Admin L5] Zaky <ops@site.dev>Satu antarmuka, banyak perilaku — dan duck typing Python.
Polimorfisme berarti "banyak bentuk": objek berbeda class merespons method yang sama dengan caranya sendiri. Kucing.bersuara() menghasilkan "meong", Anjing.bersuara() "guk" — kode pemanggil tidak perlu tahu class apa, cukup method bersuara() tersedia.
Python memungkinannya lewat duck typing: "jika berjalan seperti bebek dan bersuara seperti bebek, ia bebek". Tidak ada interface wajib — yang penting objek PUNYA method yang dipanggil. Error hanya muncul saat method tidak ada (AttributeError).
Operator overloading adalah polimorfisme pada operator: __str__ mengatur print(), __eq__ mengatur ==, __add__ mengatur +. Definisikan method khusus ini di class untuk mengubah perilaku bawaan.
Loop memanggil bersuara pada dua class berbeda — duck typing memastikan keduanya bekerja tanpa interface. Uang mengoverload __str__ dan __add__ sehingga print dan operator + berperilaku kustom.
Uji: overload __add__ pada Jarak — Jarak(3)+Jarak(7) harus `10 km`.
class Kucing:
def bersuara(self): return "meong"
class Anjing:
def bersuara(self): return "guk guk"
for hewan in [Kucing(), Anjing()]:
print(hewan.bersuara())
class Uang:
def __init__(self, jumlah):
self.jumlah = jumlah
def __str__(self):
return f"Rp{self.jumlah:,}"
def __add__(self, lain):
return Uang(self.jumlah + lain.jumlah)
print(Uang(15000) + Uang(25000)) # Rp40.000Kontrak wajib via ABC, dan boilerplate yang hilang via dataclass.
Abstract Base Class (ABC) mendefinisikan kontrak yang HARUS dipenuhi class anak: method bertanda @abstractmethod wajib dioverride — lupa berarti error saat instansiasi. Ini berbeda dari duck typing murni: ABC memaksa kepatuhan sejak desain.
from abc import ABC, abstractmethod; class Bentuk(ABC): lalu @abstractmethod def luas(self): pass. Semua class anak (Persegi, Lingkaran) WAJIB implement luas() sendiri — setiap bentuk punya cara menghitungnya.
@dataclass (Python 3.7+) menghapus boilerplate constructor: @dataclass di atas class otomatis membuat __init__, __repr__, dan __eq__ dari type annotations. Class data 10 baris menjadi 4 baris — sangat populer untuk model data dan DTO.
Bentuk(ABC) memaksa Persegi mengimplementasikan luas(). @dataclass menghasilkan constructor, repr, dan eq dari annotations — bandingkan dengan versi manual yang butuh 10+ baris. Default value stok=0 bekerja seperti parameter biasa.
Uji: @dataclass Siswa — Siswa("Ari", 95) harus `Siswa(nama='Ari', poin=95)`.
from abc import ABC, abstractmethod
class Bentuk(ABC):
@abstractmethod
def luas(self): pass
class Persegi(Bentuk):
def __init__(self, sisi):
self.sisi = sisi
def luas(self):
return self.sisi ** 2
print(Persegi(4).luas()) # 16
# dataclass: boilerplate hilang
from dataclasses import dataclass
@dataclass
class Produk:
nama: str
harga: int
stok: int = 0
p = Produk("Kopi", 18000)
print(p) # Produk(nama='Kopi', harga=18000, stok=0)Bungkus fungsi dengan perilaku tambahan tanpa mengubah isinya.
Decorator adalah fungsi yang menerima fungsi lain, membungkusnya dengan perilaku tambahan, lalu mengembalikan versi berlapis. Bentuk @nama_decorator di atas def adalah gula sintaks untuk fungsi = decorator(fungsi).
Contoh nyata: pencatat waktu (timing), cache hasil (@lru_cache), validasi input, autentikasi. Standard library memakainya luas: @property, @staticmethod, @classmethod, @dataclass — semua decorator.
Menulis decorator sendiri: fungsi luar menerima func, fungsi dalam (wrapper) menjalankan func dengan argumen aslinya ditambah perilaku sebelum/sesudah, lalu mengembalikan wrapper. functools.wraps(func) menjaga nama dan docstring asli tetap terlihat.
@ukur_waktu membungkus hitung_berat: sebelum eksekusi catat waktu, sesudahnya cetak durasinya. fungsi asli tetap utuh — decorator menambah lapisan tanpa menyentuh isinya. *args/**kwargs meneruskan semua argumen apa pun bentuknya.
Uji: @panggil_dua_kali — f() mencetak `halo` dua kali.
import time
import functools
def ukur_waktu(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
mulai = time.perf_counter()
hasil = func(*args, **kwargs)
durasi = time.perf_counter() - mulai
print(f"{func.__name__}: {durasi:.4f}s")
return hasil
return wrapper
@ukur_waktu
def hitung_berat(n):
return sum(range(n))
print(hitung_berat(1_000_000))Tangkap error tanpa program mati, dengan raise dan finally.
Python menangani error lewat exception: int("abc") melempar ValueError yang menghentikan program. try/except menangkapnya: bungkus kode berisiko di try, tangani di except — program tetap hidup. Bentuk lengkapnya empat blok: try (kode berisiko), except (saat error), else (saat sukses), finally (selalu, cocok untuk cleanup).
Tipe exception yang umum: ValueError (konversi gagal), TypeError (operasi tipe salah), ZeroDivisionError, IndexError (indeks di luar), KeyError (kunci dict tidak ada), FileNotFoundError. Tangkap tipe spesifik alih-alih Exception yang telanjang — menelan semua error menyembunyikan bug.
raise melempar exception sendiri: raise ValueError("harga tidak boleh negatif"). Ini cara fungsi memberi tahu pemanggil bahwa masalah terjadi — pemanggil yang menangkap atau meneruskannya.
Fungsi bagi melempar raise saat pembagi nol; try menangkapnya tanpa mematikan program. else berjalan saat try sukses; finally selalu — cocok untuk menutup berkas atau koneksi. Loop baca-ulang dengan try/except memvalidasi input hingga sah.
Uji: input `abc` lalu `60` — harus berakhir `60`.
def bagi(a, b):
if b == 0:
raise ZeroDivisionError("pembagi tidak boleh nol")
return a / b
try:
hasil = bagi(10, 2)
except ZeroDivisionError as e:
print(f"Gagal: {e}")
else:
print(f"Hasil: {hasil}")
finally:
print("Selesai.")
# input aman dengan loop
while True:
try:
umur = int(input("Umur: "))
if 1 <= umur <= 120:
break
print("Di luar rentang wajar.")
except ValueError:
print("Angka saja ya.")Baca dan tulis berkas dengan with open.
Buka berkas dengan open(nama, mode) — mode "r" baca, "w" tulis (timpa), "a" tambah di akhir, "r+" baca+tulis. Cara modern: with open("data.txt") as f: — with otomatis menutup berkas saat blok selesai, apa pun yang terjadi (termasuk error). Tanpa with, f.close() wajib manual dan mudah terlupa.
Membaca: f.read() seluruh isi sebagai string, f.readlines() list per baris, atau for baris in f: iterasi hemat memori. Menulis: f.write(teks) — TANPA baris baru otomatis, tambahkan \n sendiri.
Modul os untuk direktori: os.listdir("."), os.makedirs("a/b/c", exist_ok=True) membuat bertingkat, os.path.join() merangkai path lintas platform. Untuk operasi berkas tingkat tinggi, pathlib.Path adalah alternatif modern berbasis objek.
with menjamin berkas tertutup otomatis — tanpa perlu f.close() manual. Mode "w" menimpa berkas lama; "a" menambah di akhir tanpa menyentuh isi sebelumnya. enumerate(f, 1) menomori baris mulai dari 1.
Uji: tulis 2 baris ke catatan.txt, baca ulang, cetak jumlah — harus `2`.
# tulis
with open("catatan.txt", "w") as f:
f.write("baris pertama\n")
f.write("baris kedua\n")
# baca per baris
with open("catatan.txt", "r") as f:
for i, baris in enumerate(f, 1):
print(f"{i}: {baris.strip()}")
# tambah di akhir
with open("catatan.txt", "a") as f:
f.write("baris ketiga\n")
import os
print(os.listdir("."))Baca-tulis data terstruktur dengan modul csv dan json.
Modul csv membaca berkas CSV tanpa manual split koma (yang rapuh saat nilai berisi koma): csv.reader memberi list per baris, csv.DictReader memberi dict per baris dengan header sebagai kunci. Menulis: csv.writer dengan writerow(list).
Modul json mengubah Python ↔ JSON: json.dumps(obj) menghasilkan string JSON, json.loads(teks) mengubah string JSON jadi objek Python. Dump ke berkas: json.dump(obj, f, indent=2); baca dari berkas: json.load(f). Mapping tipe otomatis: dict↔object, list↔array, str↔string, int/float↔number, True/False↔true/false, None↔null.
CSV cocok untuk data tabular sederhana (ekspor spreadsheet); JSON untuk data bertingkat dan API modern. Keduanya ada di standard library — tanpa instalasi.
dumps dengan indent=2 menghasilkan JSON berformat rapi untuk dibaca manusia. loads membaca teks JSON kembali menjadi dict/list Python. dump/load bekerja langsung ke/dari berkas — tidak perlu read/write manual.
Uji: dumps/loads roundtrip — akses ["umur"], harus `17`.
import json
# Python → JSON → Python
data = {"nama": "Ari", "umur": 17, "hobi": ["coding", "game"]}
teks = json.dumps(data, indent=2)
print(teks)
kembali = json.loads(teks)
print(kembali["hobi"][0]) # coding
# JSON ke berkas
with open("data.json", "w") as f:
json.dump(data, f)
with open("data.json") as f:
hasil = json.load(f)
print(hasil["nama"])Baca argumen dan flags dari baris perintah.
sys.argv adalah cara mentah: list berisi seluruh argumen — indeks 0 nama skrip, sisanya apa pun yang diketik. Cukup untuk kasus sederhana, tapi parsing opsi --nama nilai manual rawan salah.
argparse memberikan parsing raya: deklarasikan tiap opsi dengan add_argument, panggil parse_args(), akses lewat args.nama. Flag Boolean cukup --verbose saja; bernilai --port 8080. Sisa argumen non-flag di args.Args. --help otomatis terpasang beserta deskripsi dari help parameter.
argparse juga mendukung tipe (type=int), nilai bawaan (default), pilihan terbatas (choices), dan required=True. Satu parser menutup seluruh kebutuhan CLI modern tanpa pustaka luar.
Dengan perintah python main.py 100000 --diskon 20: harga=100000 (posisional), diskon=20 (flag bernilai), verbose=False. Coba --help untuk melihat dokumentasi otomatis dari help parameter.
Uji: argparse default harga=100, diskon=10% — tanpa argumen harus `90`.
import argparse
parser = argparse.ArgumentParser(description="Kalkulator diskon")
parser.add_argument("harga", type=int, help="harga asli")
parser.add_argument("--diskon", type=int, default=10, help="persen diskon")
parser.add_argument("--verbose", action="store_true", help="tampilkan detail")
args = parser.parse_args()
hasil = args.harga - (args.harga * args.diskon // 100)
if args.verbose:
print(f"Harga: {args.harga}, diskon {args.diskon}%")
print(f"Bayar: {hasil}")Switch-case modern Python 3.10+ dengan destructuring.
match/case adalah switch-case modern Python (3.10+): satu nilai menghadapi banyak pola. Bedanya dari switch klasik: pola bisa berupa literal (case 200:), tipe (case int():), sequence (case [x, y]:), dict (case {"nama": n}:), bahkan guard (case n if n > 100:). Penulisan case int: justru menangkap nilai ke variabel bernama int, bukan menguji tipe.
Destructuring adalah kunci: case [aksi, nilai]: memecah list dua elemen langsung ke variabel. Ini menggantikan if/elif panjang untuk command dispatch — case "tambah":, case "hapus": lebih terbaca.
Pola bisa digabung dengan | (or): case 200 | 201 | 202: cocok untuk salah satu. Wildcard _ menampung sisanya. Tidak ada fallthrough — tiap case berdiri sendiri seperti yang diharapkan.
Destructuring ["tambah", x, y] memecah list dan mengikat x, y langsung; guard if len(nama) > 2 menyaring pola info. Wildcard _ menampung sisanya. Ini jauh lebih terbaca daripada if/elif berantai dengan indexing manual.
Uji: match ["tambah",10,20]→`30`; ["kurang",10,20]→`-10`.
Latihan ini memerlukan Python 3.10 atau lebih baru. Compiler situs memakai Python 3.8.1; salin kode dari editor dan jalankan dengan Python versi baru di komputermu.
def proses(perintah):
match perintah:
case ["tambah", x, y]:
return x + y
case ["kurang", x, y]:
return x - y
case ["info", nama] if len(nama) > 2:
return f"Halo {nama}"
case _:
return "Tidak dikenal"
print(proses(["tambah", 3, 5])) # 8
print(proses(["kurang", 10, 4])) # 6
print(proses(["info", "Ari"])) # Halo Ari
print(proses(["hapus"])) # Tidak dikenalAnotasi tipe opsional dan operator penugasan dalam ekspresi.
Python tetap dinamis, tapi type hints menambah petunjuk tipe yang dibaca alat (mypy, IDE): def hitung(harga: int, diskon: float) -> float:. Python tidak otomatis menolak argumen yang salah tipe, tetapi ekspresi anotasi diproses saat fungsi didefinisikan; karena itu anotasi yang belum didukung runtime tetap bisa menyebabkan error. Manfaatnya: autocomplete lebih akurat, bug tipe tertangkap sebelum jalan, dan kode tim lebih terbaca.
Tipe yang umum: int, float, str, bool, list[int] (Python 3.9+), dict[str, int], Optional[int] (bisa None), Union[int, str]. Pada Python 3.8 di editor situs, gunakan List[int] dari typing sebagai pengganti list[int].
Walrus operator := (Python 3.8+) menugaskan dan menghasilkan nilai dalam SATU ekspresi: while (teks := input()) != "selesai": membaca dan memeriksa sekaligus. Mengurangi satu baris saat hasil perlu diperiksa sebelum dipakai.
Anotasi harga: int, persen: float memberi tahu pembaca dan alat apa yang diharapkan tanpa mengunci runtime. Walrus menggabungkan input() dan pemeriksaan != dalam satu kondisi while — tanpa perlu variabel sementara di luar loop.
Uji: hitung_rata([10.0,20.0,30.0]) → `20.0`.
from typing import List
def hitung_diskon(harga: int, persen: float) -> float:
return harga * (1 - persen / 100)
def cari_maks(data: List[int]) -> int:
maks: int = data[0]
for n in data:
if n > maks:
maks = n
return maks
print(hitung_diskon(100000, 20))
print(cari_maks([3, 8, 1, 9, 4]))
# walrus
teks = ""
while (teks := input("Kata (selesai=stop): ")) != "selesai":
print(f"Panjang: {len(teks)}")Kelompokkan konstanta bernama dalam satu tipe.
Enum (enumeration) mendefinisikan kelompok konstanta bernama: class Warna(Enum): MERAH = 1, HIJAU = 2, BIRU = 3. Ini menggantikan angka sihir (0, 1, 2) dengan nama yang terbaca — Warna.MERAH jelas, angka 1 tidak.
Anggota enum bisa diakses lewat nama (Warna.MERAH) atau nilai (Warna(1) memberi Warna.MERAH). name dan value memberi keduanya. Iterasi for w in Warna: menyusuri seluruh anggota. Enum bisa jadi kunci dict dan dibandingkan dengan == atau is.
Auto-numbering: from enum import Enum, auto; MERAH = auto() memberi nilai otomatis berurutan — tak perlu menomori manual. Python 3.11+ menambah StrEnum untuk anggota yang berperilaku seperti string.
Enum mengubah "diskon level 3" menjadi "diskon Level.GOLD" — jelas dan aman dari salah ketik. Iterasi menyusuri anggota; dict berenum sebagai kunci adalah pola yang bersih untuk lookup berbasis level/status.
Uji: enum Hari, Hari(3).name harus `RABU`.
from enum import Enum
class Level(Enum):
BRONZE = 1
SILVER = 2
GOLD = 3
member = Level.GOLD
print(member.name, member.value)
for lv in Level:
print(lv)
# sebagai kunci dict
diskon = {Level.BRONZE: 5, Level.SILVER: 10, Level.GOLD: 20}
print(f"Diskon {member.name}: {diskon[member]}%")Protokol di balik for loop: __iter__ dan __next__.
Iterable adalah objek yang bisa di-loop: list, string, dict, file — semua iterable. Iterator adalah objek yang MELAKUKAN iterasi: punya __next__() yang mengembalikan elemen berikutnya dan melempar StopIteration saat habis. iter() mengubah iterable jadi iterator; next() maju satu langkah.
For loop Python bekerja lewat protokol ini: ia memanggil iter() pada objek, lalu next() berulang sampai StopIteration. Memahaminya membuka pemahaman generator, comprehension, dan zip/enumerate/map — semuanya dibangun di atasnya.
Zip dan enumerate adalah iterator yang paling sering dipakai: zip(a, b) memasangkan dua list, enumerate(a) memberi indeks+elemen. Keduanya lazy — elemen dihasilkan saat diminta, bukan disimpan di memori.
iter() mengambil iterator dari list; next() maju satu elemen per panggilan. Setelah elemen ketiga, panggilan keempat melempar StopIteration — sinyal habis yang ditangkap for loop secara otomatis. zip memasangkan dua list sejajar tanpa indeks manual.
Uji: zip 2 list ke dict — harus `{'a': 1, 'b': 2, 'c': 3}`.
angka = [10, 20, 30]
it = iter(angka)
print(next(it)) # 10
print(next(it)) # 20
print(next(it)) # 30
# next(it) lagi akan melempar StopIteration
# zip: pasangkan dua list
nama = ["andi", "budi", "citra"]
nilai = [85, 92, 78]
for n, s in zip(nama, nilai):
print(f"{n}: {s}")Fungsi yang menghasilkan nilai satu per satu, hemat memori.
Generator adalah fungsi yang memakai yield alih-alih return: setiap yield menghasilkan SATU nilai lalu menjeda eksekusi — state lokal (variabel, posisi) tetap terjaga. Saat elemen berikutnya diminta, eksekusi melanjutkan dari titik jeda itu. return mengakhiri generator.
Keunggulannya: LAZY. range(1_000_000) tidak menyimpan sejuta angka — ia menghasilkan satu per satu saat diminta. Generator expression (x**2 for x in range(10)) adalah comprehension tanpa kurung siku, menghasilkan iterator bukan list.
Use case: membaca berkas besar baris per baris tanpa memuat semuanya, pipeline transformasi data, dan infinite sequence (yield nilai berikutnya selamanya tanpa habis memori).
yield a memberi nilai lalu MENJEDA — variabel a dan b tetap hidup antar pemanggilan. Generator expression di dalam sum() tidak membangun list perantara: angka dihitung dan dijumlahkan satu per satu.
Uji: list(fib(6)) harus `[0, 1, 1, 2, 3, 5]`.
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for fib in fibonacci(8):
print(fib, end=" ") # 0 1 1 2 3 5 8 13
print()
# generator expression
kuadrat = (x**2 for x in range(5))
print(list(kuadrat))
print(sum(x**2 for x in range(10))) # tanpa list perantaraJalankan string sebagai kode — kekuatan besar, risiko besar.
eval(teks) mengevaluasi EKSPRESI string dan mengembalikan hasilnya: eval("2 + 3") memberi 5. exec(blok) menjalankan STATEMENT string: exec("for i in range(3): print(i)") mencetak 0 1 2. Keduanya menjalankan kode Python dari teks saat runtime.
Bahayanya nyata: eval(input()) pada program yang dijalankan pengguna memberi mereka akses mengeksekusi kode APA PUN di mesinmu — membaca berkas, menghapus data, memasang backdoor. Aturan emas: JANGAN PERNAH eval/exec input yang tidak kamu kendalikan penuh.
Kegunaan yang sah: kalkulator ekspresi matematika dengan sanitasi ketat, plugin system yang memuat kode terpercaya, dan REPL. Untuk kasus kebanyakan, ast.literal_eval() adalah alternatif aman — hanya menerima literal Python (angka, string, list, dict) tanpa eksekusi kode.
eval cocok untuk ekspresi tunggal; exec untuk blok. ast.literal_eval hanya menerima literal (list, dict, angka, string) dan MENOLAK ekspresi seperti __import__ — pengganti aman saat data berasal dari luar.
Uji: eval("2 ** 10") harus `1024`.
import ast
# eval: ekspresi
print(eval("2 ** 10"))
print(eval("len([1, 2, 3])"))
# exec: statement
exec("x = 42\nprint(x)")
# alternatif aman: ast.literal_eval
teks = "[1, 2, 3]"
data = ast.literal_eval(teks)
print(data, type(data))Proyek penutup: gabungan random, while, if, dan input.
Proyek ini menggabungkan hampir semua yang sudah dipelajari: variabel, input, konversi tipe, perulangan while, kondisi if/elif/else, modul random, dan penanganan exception. Program memilih angka rahasia 1-100, pemain menebak, program memberi petunjuk "terlalu tinggi" atau "terlalu rendah" sampai benar.
Struktur logikanya: (1) pilih angka rahasia dengan random.randint(1, 100); (2) loop: baca tebakan, bandingkan dengan rahasia; (3) beri umpan balik arah; (4) saat benar, cetak jumlah percobaan dan keluar.
Kerangka sudah disiapkan di editor — lengkapi bagian bertanda TODO sampai program berjalan penuh. Ini pola klasik yang dipakai di course CodeWithHarry dan banyak tutorial Python sebagai penutur modul dasar.
Program penuh yang bisa langsung dijalankan. Kerangka di editor latihan menyembunyikan bagian pembanding — lengkapi sampai keluarannya benar. Peningkatan opsional: batasi percobaan, main lagi?, atau mode dua pemain.
Uji: lengkapi perbandingan tebakan agar game berjalan benar (petunjuk naik/turun, akhiri saat benar).
import random
rahasia = random.randint(1, 100)
percobaan = 0
print("=== TEBAK ANGKA 1-100 ===")
while True:
teks = input("Tebakanmu: ")
tebakan = int(teks)
percobaan += 1
if tebakan < rahasia:
print("Terlalu rendah!")
elif tebakan > rahasia:
print("Terlalu tinggi!")
else:
print(f"Benar! {percobaan} percobaan.")
breakSuit vs komputer dengan random.choice dan match/case.
Snake-Water-Gun adalah variant rock-paper-scissors dari CodeWithHarry: ular minum air, air mematikan senjata, senjata membunuh ular. Pemain memilih, komputer memilih acak, pemenang ditentukan. Proyek ini menggabungkan random.choice, dictionary, match/case, dan loop skor.
Logika kemenangan bisa dipetakan sebagai dict: MENANG = {"ular": "air", "air": "senjata", "senjata": "ular"} — kunci mengalahkan nilai. Bila pilihan sama: seri. Bila pilihan pemain mengalahkan pilihan komputer (MENANG[pemain] == komputer): menang; selain itu kalah.
Struktur game loop: while True menampilkan skor, baca input, validasi, tentukan ronde, perbarui skor, tanya main lagi. Break keluar saat pemain menyerah. Kerangka ada di editor — lengkapi penentuan pemenangnya.
Dictionary MENANG memetakan siapa mengalahkan siapa — logika tiga cabang dalam satu tabel. Loop baca-validasi-putuskan-skor adalah pola game loop standar. Kerangka editor menyembunyikan penentuan pemenang — lengkapi hingga skor berjalan benar.
Uji: lengkapi penentuan pemenang agar skor terupdate setiap ronde.
import random
MENANG = {"ular": "air", "air": "senjata", "senjata": "ular"}
pilihan = ["ular", "air", "senjata"]
skor_p, skor_k = 0, 0
print("=== SNAKE WATER GUN ===")
while True:
aku = input("[ular/air/senjata/keluar]: ").lower()
if aku == "keluar":
break
if aku not in pilihan:
print("Pilihan tidak dikenal.")
continue
komputer = random.choice(pilihan)
print(f"Komputer: {komputer}")
if aku == komputer:
print("Seri!")
elif MENANG[aku] == komputer:
print("Kamu menang!")
skor_p += 1
else:
print("Komputer menang!")
skor_k += 1
print(f"Skor: kamu {skor_p} - {skor_k} komputer")