Saat jumlah module bertambah, menumpuk seluruh file .py dalam satu folder membuat proyek kembali sulit dinavigasi: file laporan bercampur dengan file pembayaran, dan nama mulai bertabrakan. Python menjawabnya dengan package — folder yang mengelompokkan module — dan subpackage — package di dalam package. Pada Chapter ini kita membangun package bertingkat untuk sebuah toko daring, mempelajari peran file __init__.py, dan memakai nama bertitik seperti toko.produk.katalog untuk menjangkau isinya.

Package adalah Folder Berisi Module #

Sebuah folder menjadi package Python bila di dalamnya ada file khusus bernama __init__.py. File tersebut boleh kosong — perannya baru dibedah tuntas pada Chapter init.py. Untuk sekarang, kehadirannya saja sudah cukup untuk menandai “folder ini adalah package”.

Kita bangun struktur proyek toko berikut:

text
belajar/
├── kasir.py
└── toko/
    ├── __init__.py
    ├── produk/
    │   ├── __init__.py
    │   └── katalog.py
    └── pembayaran/
        ├── __init__.py
        └── metode.py

Package utama toko berisi dua subpackage: produk dan pembayaran — masing-masing adalah package sendiri karena foldernya berisi __init__.py. Isi katalog.py:

python
PRODUK = {
    "P001": ("Kopi Arabika", 85000),
    "P002": ("Teh Melati", 45000),
}

def cari_produk(kode):
    nama, harga = PRODUK[kode]
    return f"{nama} - Rp{harga}"

Isi metode.py:

python
def cek_bayar(total, dibayar):
    if dibayar >= total:
        kembalian = dibayar - total
        return f"Lunas, kembalian Rp{kembalian}"
    return "Kurang bayar"

Dari luar package, semua diakses dengan nama bertitik — folder menjadi bagian dari nama:

python
import toko.produk.katalog
from toko.pembayaran.metode import cek_bayar

print(toko.produk.katalog.cari_produk("P001"))
print(cek_bayar(85000, 100000))

Output yang Dihasilkan:

text
Kopi Arabika - Rp85000
Lunas, kembalian Rp15000

Mari kita bedah kasir.py baris per baris:

  1. Baris 1 (import toko.produk.katalog): interpreter mencari toko, lalu produk di dalamnya, lalu katalog — tiga tingkat nama yang dipisahkan titik dan dijalankan berurutan dari yang paling luar.
  2. Baris 2 (from toko.pembayaran.metode import cek_bayar): bentuk from menelusuri jalur package yang sama, tetapi hanya mengikat nama cek_bayar langsung di program kita.
  3. Baris 4 (toko.produk.katalog.cari_produk("P001")): function diambil dari module katalog di dalam subpackage produk dengan menuliskan seluruh jalurnya.

Perbedaan Module dan Package #

AspekModulePackage
Wujudsatu file .pyfolder berisi __init__.py
Nama Pythonnama filenama folder
Contohkatalogtoko.produk
Isifunction, konstanta, classmodule dan subpackage
Cara mengimporimport katalogimport toko.produk

Baris pemisah keduanya memang tipis — package secara teknis juga module — tetapi bagi pembaca kode, kata “module” berarti satu file dan “package” berarti folder. Standard library sendiri memakai keduanya: math adalah module tunggal, sedangkan json yang sering kita pakai sebenarnya package berisi beberapa file.

Satu detail penting dari struktur di atas: setiap tingkat folder yang berperan sebagai package membutuhkan __init__.py-nya sendiri — toko/, toko/produk/, dan toko/pembayaran/ masing-masing punya satu. Kedalaman bertingkat seperti toko.produk.katalog membantu pengelompokan, tetapi jangan berlebihan: setiap tingkat menambah satu segmen pada setiap import yang menuliskannya. Aturan praktisnya, pecah folder menjadi subpackage hanya ketika jumlah file di dalamnya sudah membuat navigasi sulit — untuk lima module, satu package datar biasanya masih lebih nyaman dibaca.

Mengimpor Package Tidak Serta-merta Memuat Isinya #

Jebakan klasik: import toko tidak otomatis memuat toko.produk.katalog. Import sebuah package hanya menjalankan __init__.py-nya — tidak menyentuh module di dalamnya. Akibatnya kode berikut gagal:

python
import toko

print(toko.produk.katalog.PRODUK["P002"])

Output yang Dihasilkan:

text
Traceback (most recent call last):
  File "/home/budi/belajar/kasir2.py", line 3, in <module>
    print(toko.produk.katalog.PRODUK["P002"])
          ^^^^^^^^^^^
AttributeError: module 'toko' has no attribute 'produk'

Statement import toko membuat nama toko tersedia, tetapi attribute produk belum pernah dimuat ke dalamnya. Aturannya: module yang ingin dipakai harus diimpor eksplisit — import toko.produk.katalog — atau dimuat otomatis lewat __init__.py (trik yang dibahas pada Chapter berikutnya tentang init.py).

Dengan package dan subpackage, proyek kita kini punya struktur. Pertanyaan berikutnya: apa sebenarnya yang boleh dan sebaiknya dituliskan di dalam file __init__.py itu? Chapter berikutnya menjawabnya sekaligus menunjukkan cara merapikan wajah publik sebuah package.