Bab 11 — Modul dan Package: Meminjam Alat dari Gudang Python
Seri B3 — Program Kecil yang Berguna
Semua skrip bab ini ada di folder kode/bab11/. Di versi web, Anda juga bisa mengunduh semuanya sekaligus (zip).
Di Bab 10, Anda menulis fungsi sendiri. Tetapi petani tidak membuat cangkul dari besi mentah setiap kali mau mencangkul: ia mengambilnya dari gudang alat. Python punya gudang alat yang besar, dan setiap rak di dalamnya disebut modul: sebuah berkas Python berisi fungsi dan data siap pakai. Gudang bawaan yang ikut terpasang bersama Python disebut pustaka standar (standard library). Anda sudah mengintipnya di Bab 4 saat memakai import; sekarang kita masuk ke gudangnya.

Tiga cara memakai import
01_impor_dasar.py
# Bab 11 - Tiga cara memakai import
import math # cara 1: bawa seluruh modul, panggil dengan awalan math.
from math import sqrt # cara 2: ambil satu alat saja
import statistics as stat # cara 3: beri nama panggilan (alias)
print("pi =", math.pi)
print("akar 144 =", sqrt(144))
print("rata-rata =", stat.mean([32.5, 45.2, 28.0]))
# Luas tajuk pohon berbentuk lingkaran dengan jari-jari 3,5 m
luas = math.pi * 3.5 ** 2
print(f"Luas tajuk = {luas:.2f} m2")pi = 3.141592653589793
akar 144 = 12.0
rata-rata = 35.233333333333334
Luas tajuk = 38.48 m2
import mathmembawa seluruh modul; alatnya dipanggil dengan awalan:math.pi.from math import sqrtmengambil satu alat saja, lalu dipakai tanpa awalan.import statistics as statmemberi nama panggilan (alias) agar lebih pendek.
Awalan itu berguna: math.pi langsung memberi tahu bahwa pi berasal dari modul math, bukan variabel Anda sendiri.
Tulis semua import di bagian paling atas skrip. Pembaca langsung tahu alat apa yang dibutuhkan program.
math dan random
02_math_acak.py
# Bab 11 - math dan random (dengan benih supaya hasilnya bisa diulang)
import math
import random
print(math.ceil(4.2), math.floor(4.8), round(4.5), round(5.5)) # pembulatan
random.seed(42) # benih: urutan "acak" jadi tetap
plot_terpilih = random.choice(["A", "B", "C"])
sampel = random.sample(range(1, 101), 5) # 5 nomor pohon berbeda dari 1..100
cuaca = random.randint(24, 33) # bilangan bulat 24..33
print("Plot terpilih:", plot_terpilih)
print("Pohon contoh :", sampel)
print("Suhu tiruan :", cuaca)
random.seed(42) # benih yang sama -> hasil yang sama
print("Ulang :", random.choice(["A", "B", "C"]), random.sample(range(1, 101), 5))5 4 4 6
Plot terpilih: C
Pohon contoh : [15, 4, 95, 36, 32]
Suhu tiruan : 27
Ulang : C [15, 4, 95, 36, 32]
Baris pertama menunjukkan kejutan: round(4.5) menghasilkan 4, tetapi round(5.5) menghasilkan 6. Python membulatkan angka yang tepat di tengah ke bilangan genap terdekat, bukan selalu ke atas. Aturan ini disebut pembulatan bankir; yang perlu Anda ingat, jangan heran bila hasilnya begitu.
Modul random menghasilkan angka “acak”. Dengan random.seed(42) kita menetapkan benih: titik awal urutan acak. Benih sama, urutan sama; lihat baris terakhir yang mengulang hasil C [15, 4, 95, 36, 32]. Inilah cara membuat data tiruan yang bisa diulang persis. Satu catatan jujur: dokumentasi Python hanya menjamin urutan random.random() tetap sama untuk benih yang sama di versi Python mendatang, sedangkan choice dan sample bisa berubah antarversi. Jadi angka di atas pasti sama di komputer Anda bila versi Python-nya sama, tetapi jangan membangun sistem yang bergantung pada angka itu.
Tanggal dengan datetime
03_tanggal.py
# Bab 11 - datetime: tanggal tanam, umur, dan perkiraan panen
from datetime import date, timedelta
tanam = date(2026, 3, 1)
panen = tanam + timedelta(days=120) # padi contoh: 120 hari
umur = date(2026, 5, 15) - tanam # selisih dua tanggal = timedelta
print("Tanam :", tanam)
print("Panen :", panen.strftime("%d-%m-%Y"))
print("Umur pada 15 Mei 2026:", umur.days, "hari")
print("Dari teks:", date.fromisoformat("2026-07-01"))
nama_hari = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"]
print("Hari panen jatuh pada:", nama_hari[panen.weekday()])Tanam : 2026-03-01
Panen : 29-06-2026
Umur pada 15 Mei 2026: 75 hari
Dari teks: 2026-07-01
Hari panen jatuh pada: Senin
date(2026, 3, 1) membuat tanggal. Menambah timedelta(days=120) menggeser tanggalnya. Selisih dua tanggal adalah timedelta, dan .days mengambil jumlah harinya (75 hari dari 1 Maret sampai 15 Mei). strftime("%d-%m-%Y") mengatur tampilan tanggal. (Kita sengaja tidak memakai date.today() karena hasilnya berubah setiap hari.)
statistics dan collections
04_statistik.py
# Bab 11 - statistics: ringkasan angka tanpa menulis rumus sendiri
import statistics
bobot_g = [520, 480, 560, 540, 480, 505] # bobot sampel ikan (angka contoh)
print("rata-rata :", round(statistics.mean(bobot_g), 2))
print("median :", statistics.median(bobot_g))
print("modus :", statistics.mode(bobot_g))
print("simpangan :", round(statistics.stdev(bobot_g), 2))
print("terkecil/terbesar:", min(bobot_g), max(bobot_g))rata-rata : 514.17
median : 512.5
modus : 480
simpangan : 32.31
terkecil/terbesar: 480 560
Enam bobot ikan itu menghasilkan rata-rata 514,17 g dan median 512,5 g (nilai tengah setelah diurutkan). Modus 480 adalah angka yang paling sering muncul. stdev (simpangan baku) mengukur seberapa menyebar angkanya; makin besar, makin tidak seragam ikannya.
05_koleksi.py
# Bab 11 - collections: Counter dan defaultdict
from collections import Counter, defaultdict
jenis = ["Jati", "Meranti", "Jati", "Mahoni", "Jati", "Meranti"]
hitung = Counter(jenis)
print(hitung)
print("Terbanyak:", hitung.most_common(1))
per_plot = defaultdict(list) # kunci baru otomatis diberi list kosong
for plot, diameter in [("A", 32.5), ("B", 28.0), ("A", 45.2), ("B", 51.5)]:
per_plot[plot].append(diameter)
print(dict(per_plot))Counter({'Jati': 3, 'Meranti': 2, 'Mahoni': 1})
Terbanyak: [('Jati', 3)]
{'A': [32.5, 45.2], 'B': [28.0, 51.5]}
Counter menghitung berapa kali tiap nilai muncul: Jati ada 3. defaultdict(list) adalah dict yang otomatis membuat list kosong untuk kunci baru, sehingga Anda bisa langsung append tanpa memeriksa dulu apakah kuncinya sudah ada.
itertools dan pathlib
06_itertools.py
# Bab 11 - itertools: kombinasi dan kelompok
from itertools import combinations, product, groupby
kolam = ["A", "B", "C"]
print("Pasangan kolam:", list(combinations(kolam, 2)))
print("Kolam x pakan :", list(product(kolam[:2], ["pelet", "cacah"])))
pohon = [("A", "Jati"), ("A", "Meranti"), ("B", "Mahoni"), ("B", "Jati")]
for plot, anggota in groupby(pohon, key=lambda p: p[0]): # data harus sudah berurutan
print(plot, [jenis for _, jenis in anggota])Pasangan kolam: [('A', 'B'), ('A', 'C'), ('B', 'C')]
Kolam x pakan : [('A', 'pelet'), ('A', 'cacah'), ('B', 'pelet'), ('B', 'cacah')]
A ['Jati', 'Meranti']
B ['Mahoni', 'Jati']
combinations membuat semua pasangan, product membuat semua kombinasi dari dua daftar, dan groupby mengelompokkan data yang sudah berurutan. Perhatikan: groupby hanya menyatukan elemen yang berdampingan, jadi urutkan dulu datanya bila belum.
07_pathlib_awal.py
# Bab 11 - pathlib: alamat berkas sebagai objek (belum menyentuh disk)
from pathlib import Path
berkas = Path("data") / "pohon.csv" # tanda / menyambung bagian alamat
print(berkas)
print("nama :", berkas.name)
print("akhiran:", berkas.suffix)
print("tanpa akhiran:", berkas.stem)
print("folder :", berkas.parent)
print("ganti akhiran:", berkas.with_suffix(".json"))
print("ada di disk?", berkas.exists())
print("skrip ini bernama:", Path(__file__).name)data\pohon.csv
nama : pohon.csv
akhiran: .csv
tanpa akhiran: pohon
folder : data
ganti akhiran: data\pohon.json
ada di disk? False
skrip ini bernama: 07_pathlib_awal.py
pathlib.Path memperlakukan alamat berkas sebagai objek. Tanda / menyambung bagian alamat. Pada komputer Windows, pemisahnya tampil sebagai \; di macOS atau Linux tampil sebagai /. Itulah keuntungan Path: Anda menulis sekali, Python menyesuaikan dengan sistemnya. Di Bab 13 kita akan memakainya untuk membaca dan menulis berkas sungguhan.
Membuat modul sendiri
Modul hanyalah berkas .py. Modul kita ada di subfolder modul/:
# modul/ukuran_lapangan.py (dua fungsi pertamanya)
def luas_bidang_dasar_m2(diameter_cm): ...
def biomassa_kg(jumlah_ikan, bobot_rata_g): ...Isi lengkapnya ada di berkas kode/bab11/modul/ukuran_lapangan.py. Skrip berikut memakainya:
08_modul_sendiri.py
# Bab 11 - Memakai modul buatan sendiri dari subfolder "modul"
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "modul")) # beri tahu Python lokasi modulnya
import ukuran_lapangan as ukuran
print(f"Luas bidang dasar 32,5 cm: {ukuran.luas_bidang_dasar_m2(32.5):.4f} m2")
print(f"Biomassa kolam A : {ukuran.biomassa_kg(800, 540.5):.1f} kg")
print("Nama modul ini:", ukuran.__name__)Luas bidang dasar 32,5 cm: 0.0830 m2
Biomassa kolam A : 432.4 kg
Nama modul ini: ukuran_lapangan
Luas bidang dasar adalah luas penampang batang; untuk diameter 32,5 cm hasilnya 0,0830 m². Python mencari modul di sejumlah folder; kita menambahkan folder modul/ ke daftarnya lewat sys.path.insert. Nama modul (ukuran_lapangan) sama dengan nama berkas tanpa .py.
if __name__ == "__main__"
Setiap modul punya variabel bawaan __name__. Bila berkas dijalankan langsung, __name__ berisi "__main__". Bila berkas di-import, __name__ berisi nama modulnya. Dengan begitu satu berkas bisa punya “uji cepat” yang hanya jalan saat dijalankan langsung:
09_main_atau_impor.py
# Bab 11 - if __name__ == "__main__": dijalankan langsung atau di-import
import subprocess
import sys
from pathlib import Path
modul = Path(__file__).parent / "modul"
sys.path.insert(0, str(modul))
import contoh_nama # di-import: __name__ = nama modul
print("--- sekarang dijalankan langsung ---")
hasil = subprocess.run([sys.executable, str(modul / "contoh_nama.py")],
capture_output=True, text=True)
print(hasil.stdout.strip())
print("--- uji cepat di modul ukuran_lapangan (dijalankan langsung) ---")
hasil = subprocess.run([sys.executable, str(modul / "ukuran_lapangan.py")],
capture_output=True, text=True)
print(hasil.stdout.strip())Di dalam contoh_nama, __name__ = contoh_nama
--- sekarang dijalankan langsung ---
Di dalam contoh_nama, __name__ = __main__
--- uji cepat di modul ukuran_lapangan (dijalankan langsung) ---
Uji cepat: 0.083 432.4
Baris pertama muncul saat contoh_nama di-import (nama modulnya contoh_nama). Setelah itu skrip menjalankan berkas yang sama sebagai program tersendiri, dan kali ini __name__ berisi __main__. Pada ukuran_lapangan.py, bagian di bawah if __name__ == "__main__": hanya tampil pada pemanggilan kedua; saat di-import di skrip 08, uji cepat itu tidak mengganggu.
Kode di tingkat paling luar modul dijalankan saat di-import. Karena itu jangan menaruh perintah panjang atau print di sana, kecuali di bawah if __name__ == "__main__":.
Package: folder berisi modul
Bila modul makin banyak, kumpulkan dalam package: folder yang berisi berkas __init__.py dan modul-modul. Package kita bernama inventaris:
inventaris/
__init__.py <- penanda package; boleh memuat daftar alat yang ditampilkan
data_inti.py <- data contoh lima sektor
hitung.py <- luas_bidang_dasar_m2, biomassa_kg
ringkas.py <- ringkas(angka)
10_paket_kecil.py
# Bab 11 - Paket kecil: folder "inventaris" berisi __init__.py dan modul-modulnya
import inventaris
from inventaris import biomassa_kg # tersedia lewat __init__.py
from inventaris.data_inti import ikan # ambil langsung dari modul di dalam paket
print("Isi paket (__all__):", inventaris.__all__)
print("Modul hitung berasal dari:", inventaris.hitung.__name__)
for kolam in ikan:
kg = biomassa_kg(kolam["jumlah"], kolam["bobot_rata_g"])
print(f"Kolam {kolam['kolam']}: {kg:.1f} kg")Isi paket (__all__): ['luas_bidang_dasar_m2', 'biomassa_kg', 'ringkas']
Modul hitung berasal dari: inventaris.hitung
Kolam A: 432.4 kg
Kolam B: 375.0 kg
Kolam C: 288.0 kg
__init__.py mengimpor alat dari modul-modulnya sehingga pemakai cukup menulis from inventaris import biomassa_kg. Kolam A berisi 800 ikan seberat 540,5 g: 432,4 kg, persis seperti hasil di Bab 10. Variabel __all__ mencatat nama-nama yang sengaja ditampilkan paket.
pip: meminjam dari luar gudang
Bila alat yang Anda butuhkan tidak ada di pustaka standar, pip memasangnya dari PyPI, toko pustaka daring milik komunitas Python. Perintahnya diketik di terminal, bukan di dalam skrip. Perintah berikut hanya contoh dan tidak dijalankan saat buku ini dibuat, karena memasang paket mengubah komputer pembaca:
python -m pip install openpyxl # memasang pustaka Excel (dipakai di Bab 15)
python -m pip list # melihat pustaka yang terpasang
python -m pip uninstall openpyxl # mencopotMenulis python -m pip (bukan sekadar pip) memastikan pip yang dipakai berasal dari Python yang sama dengan yang menjalankan skrip Anda. Bila Anda mencoba mengimpor pustaka yang belum terpasang, ini yang terjadi:
11_modul_tak_ketemu.py
# Bab 11 - Jebakan: mengimpor modul yang tidak ada
import pustaka_tak_ada
print("baris ini tidak pernah dicapai")Traceback (most recent call last):
File "11_modul_tak_ketemu.py", line 2, in <module>
import pustaka_tak_ada
ModuleNotFoundError: No module named 'pustaka_tak_ada'
Pesan ModuleNotFoundError berarti Python tidak menemukan modul bernama itu: bisa karena salah ketik, atau belum dipasang dengan pip. Pembahasan lengkap pemasangan dan lingkungan terpisah (venv) ada di Bab 17.
Saat Anda menulis import x, Python mencari x berurutan di: modul bawaan yang sudah ada, folder tempat skrip dijalankan, lalu daftar folder lain di sys.path. Karena folder skrip ada di urutan awal, Anda sebaiknya tidak menamai berkas sendiri random.py atau statistics.py: modul buatan Anda akan menutupi modul asli dan menimbulkan error yang membingungkan.
Proyek Bersambung B3: ringkasan lima sektor
Selamat datang di proyek Seri B3. Di Seri B2, data lapangan tersimpan di dalam kode. Di seri ini kita akan menyimpannya ke file, membuatnya tahan salah, dan mengubahnya menjadi laporan. Langkah pertama: kemas alat-alat kita menjadi package inventaris (yang sudah Anda lihat), lalu pakai untuk meringkas data empat tabel dari lima sektor (hutan, kebun, pertanian, perikanan, peternakan). Angka-angkanya fiktif.
12_proyek_ringkasan.py
# Bab 11 - Proyek bersambung B3: ringkasan lima sektor memakai paket sendiri
from inventaris import ringkas
from inventaris.data_inti import pohon, tanaman, ikan, ternak
sektor = {
"Hutan (diameter cm)": [p["diameter_cm"] for p in pohon],
"Kebun+sawah (kg)": [t["hasil_kg"] for t in tanaman],
"Perikanan (g/ekor)": [i["bobot_rata_g"] for i in ikan],
"Peternakan (kg)": [t["bobot_kg"] for t in ternak],
}
for nama, angka in sektor.items():
r = ringkas(angka)
print(f"{nama:22} n={r['jumlah']} total={r['total']:8.1f} rata={r['rata_rata']:7.2f} median={r['median']}")Hutan (diameter cm) n=6 total= 234.0 rata= 39.00 median=38.4
Kebun+sawah (kg) n=4 total= 1030.0 rata= 257.50 median=260.75
Perikanan (g/ekor) n=3 total= 1320.5 rata= 440.17 median=480.0
Peternakan (kg) n=4 total= 1190.0 rata= 297.50 median=369.5
Tiap baris dibaca begini: sektor hutan punya 6 pohon, total diameter 234,0 cm, rata-rata 39,00 cm, median 38,4 cm. Kebun dan sawah (padi, jagung, kopi, kakao) menghasilkan 1030,0 kg. Rata-rata bobot ikan per kolam 440,17 g, dan ternak rata-rata 297,50 kg. Perhatikan bagaimana skrip ini pendek: seluruh pekerjaan berat dikerjakan oleh package.
Latihan
- Pakai
datetime: hitung tanggal panen untuk kopi yang ditanam 15 Januari 2026 dan dipanen 270 hari kemudian, lalu cetak dengan formatdd-mm-yyyy. - Dengan
random.seed(7), pilih 3 nomor kolam berbeda dari 1 sampai 12 memakairandom.sample. Jalankan dua kali dan pastikan hasilnya sama. - Tambahkan fungsi
keliling_lingkaran_m(jari_jari_m)kemodul/ukuran_lapangan.py, lalu panggil dari skrip baru yang meng-import-nya. - Tantangan: tambahkan modul
inventaris/tanggal.pyberisi fungsitanggal_tanam(tanggal_panen, umur_hari), ekspor lewat__init__.py, lalu pakai untuk mencetak tanggal tanam tiap komoditas didata_inti.tanamanbila semuanya dipanen pada 1 Oktober 2026.
Ringkasan Bab
- Modul = berkas Python berisi alat; package = folder modul dengan
__init__.py. - Tiga bentuk impor:
import x,from x import y,import x as z. - Pustaka standar berguna:
math,random(pakaiseed),datetime,statistics,collections,itertools,pathlib. if __name__ == "__main__":memisahkan kode yang hanya jalan saat berkas dijalankan langsung.python -m pip install <nama>memasang pustaka tambahan;ModuleNotFoundErrorberarti modul tidak ditemukan.- Proyek B3 dimulai: package
inventarismeringkas data lima sektor.
Selanjutnya, di Bab 12: penanganan error, cara membuat program tidak langsung runtuh saat ada yang salah.