File __init__.py sering ditulis kosong dan tampak seperti formalitas tanpa makna. Kenyataannya, file inilah pintu depan package: isinya dijalankan setiap kali package diimpor, dan dari sinilah kita bisa merancang wajah publik package — menentukan nama apa saja yang layak dipakai pengguna. Pada Chapter ini kita isi __init__.py dengan berbagai tingkat kerumitan, dari yang kosong sampai yang membentuk API rapi dengan from ... import dan __all__.

Apa yang Berjalan Saat Package Diimpor #

Statement import toko menjalankan file toko/__init__.py — persis seperti import sapa menjalankan sapa.py. Karena itu, semua kode tingkat atas di dalam __init__.py dieksekusi pada saat import package. Kita buktikan dengan package sensor:

text
belajar/
├── program.py
└── sensor/
    ├── __init__.py
    └── suhu.py

Isi sensor/__init__.py — dua statement, bukan kosong:

python
print("Package sensor diimpor")

from . import suhu

Isi sensor/suhu.py:

python
def baca_suhu(celsius):
    return f"Suhu terbaca: {celsius} derajat Celsius"

Program utama program.py:

python
import sensor

print(sensor.suhu.baca_suhu(28))

Output yang Dihasilkan:

text
Package sensor diimpor
Suhu terbaca: 28 derajat Celsius

Mari kita bedah kejadiannya:

  1. Baris 1 (import sensor): interpreter menjalankan sensor/__init__.py — kalimat pembukanya tercetak, lalu statement from . import suhu memuat module suhu di dalam package yang sama dan menempelkannya sebagai attribute package.
  2. Baris 3 (sensor.suhu.baca_suhu(28)): berkat from . import suhu, pengguna package tidak perlu menulis import sensor.suhu sendiri — submodule sudah tersedia begitu package diimpor. Inilah obat untuk AttributeError: module 'toko' has no attribute 'produk' yang kita temui pada Chapter Package dan Subpackage.

init.py Kosong Itu Wajar #

Berdasarkan contoh di atas, sepertinya __init__.py wajib berisi sesuatu. Tidak demikian: file kosong adalah isi yang paling umum dan sepenuhnya sah. Package yang isinya sekadar kumpulan module — seperti package toko kita sebelumnya — tidak butuh apa pun di pintu depannya. Kehadiran file kosong tersebut tetap penting untuk menandai folder sebagai package biasa (regular package) dan memudahkan alat bantu pengembangan menemukannya.

Membentuk API Publik Package #

from ... import di __init__.py tidak hanya bisa memuat submodule — file tersebut juga bisa mengangkat function tertentu langsung ke level package. Bayangkan pengguna package harus menulis sensor.suhu.baca_suhu(31) setiap kali; dengan mengganti isi sensor/__init__.py menjadi satu baris, jalur itu dipendekkan:

python
from .suhu import baca_suhu

Sekarang baca_suhu adalah nama di level package. Program pengguna menjadi jauh lebih ramping:

python
from sensor import baca_suhu

print(baca_suhu(31))

Output yang Dihasilkan:

text
Suhu terbaca: 31 derajat Celsius

Keselarasan bentuk import di kedua sisi — from .suhu import baca_suhu di dalam package dan from sensor import baca_suhu di luar — membuat penulisan package terasa simetris. Prinsip desainnya: pengguna cukup tahu apa yang bisa dipakai, tanpa perlu tahu di file mana function itu didefinisikan. Kita bebas merapikan isi internal tanpa memecah kode pengguna.

all Menyaring Nama Publik #

Daftar nama __all__ menentukan nama apa saja yang diekspor bila pengguna menulis from module import *. Karena star import tetap mengambil semua nama publik secara bawaan, __all__ berperan sebagai daftar tamu resmi. Contoh module utilitas.py:

python
__all__ = ["format_rupiah"]

def format_rupiah(angka):
    return f"Rp{angka:,}".replace(",", ".")

def _catatan_internal():
    return "hanya untuk di dalam module"

def bantu_lainnya():
    return "tidak masuk daftar __all__"

Program pengguna melakukan star import:

python
from utilitas import *

print(format_rupiah(1250000))
print(bantu_lainnya())

Output yang Dihasilkan:

text
Rp1.250.000
Traceback (most recent call last):
  File "/home/budi/belajar/belanja.py", line 4, in <module>
    print(bantu_lainnya())
          ^^^^^^^^^^^^^
NameError: name 'bantu_lainnya' is not defined

Traceback lengkap menampilkan jalur file sesuai komputer tempat program dijalankan — pesan intinya sama di mana pun. Dua hal terjadi di sini:

  1. format_rupiah berhasil dipakai karena namanya tercantum di dalam list __all__.
  2. bantu_lainnya menimbulkan NameError meskipun didefinisikan publik — star import hanya mengambil nama di __all__ bila daftar itu ada.

Sedangkan nama _catatan_internal tidak ikut dalam kedua kasus: tanpa __all__, star import memang sudah melewati semua nama yang diawali garis bawah, sehingga awalan _ menjadi konvensi penanda “urusan dalam negeri” module.

Sampai di sini, semua import di dalam package kita memakai bentuk relative — from . import suhu. Chapter berikutnya membedah dua gaya import tersebut secara berdampingan: absolute dan relative, beserta aturan kapan masing-masing layak dipilih.