Modul adalah berkas Python berisi definisi dan pernyataan yang dapat dipakai ulang oleh berkas lain melalui pernyataan import. Program yang besar hampir selalu dipecah ke dalam beberapa modul, sehingga mekanisme import menjadi fondasi bagi seluruh pengorganisasian kode pada topik-topik berikutnya. Topik ini membahas bentuk-bentuk pernyataan import, jalur pencarian yang ditempuh Python untuk menemukan sebuah modul, dan kebiasaan interpreter mengeksekusi modul hanya satu kali. Idiom if __name__ == "__main__" juga dibahas sebagai alat membedakan kode yang diimpor dari kode yang dijalankan langsung.
Bentuk-bentuk pernyataan import#
Pernyataan import memiliki tiga bentuk yang masing-masing mengikat nama dengan cara berbeda. Bentuk import modul membuat seluruh isi modul dapat diakses melalui nama modulnya, bentuk from modul import nama menarik satu nama tertentu ke dalam namespace saat ini, yaitu kumpulan nama yang berlaku pada satu lingkup kode, dan bentuk import modul as alias memberi nama singkat untuk modul yang panjang.
import math
from statistics import mean
import statistics as stats
print(math.sqrt(144))
print(mean([2, 4, 6]))
print(stats.median([3, 1, 2]))12.0
4
2Bentuk pertama menaruh fungsi sqrt di balik awalan math., sehingga asal setiap nama tetap terlihat pada tempat pemakaiannya. Bentuk kedua mengimpor mean secara langsung, dan hasilnya berupa bilangan bulat karena seluruh masukannya bilangan bulat. Bentuk ketiga mengikat modul statistics ke nama singkat stats, yang berguna ketika nama modul ditulis berkali-kali. Ketiganya dapat dicampur dalam satu berkas sesuai kebutuhan keterbacaan.
Membuat dan mengimpor modul sendiri#
Setiap berkas berekstensi .py adalah modul, dan mengimpornya sama saja dengan mengeksekusi seluruh isi berkas tersebut dari atas ke bawah. Karena itu, variabel dan fungsi yang didefinisikan di tingkat atas modul dapat diakses sebagai atribut setelah impor berhasil. Contoh berikut menulis berkas modul ke direktori sementara, lalu mengimpornya.
import sys
import tempfile
from pathlib import Path
# menulis berkas modul contoh ke direktori sementara
direktori = Path(tempfile.mkdtemp(prefix="contoh-modul-"))
(direktori / "salam.py").write_text(
'PENYAPA = "Halo dari modul salam"\n'
'print("modul salam dieksekusi")\n',
encoding="utf-8",
)
# sebelum jalurnya didaftarkan, modul belum dapat diimpor
try:
import salam
except ModuleNotFoundError as e:
print("gagal:", str(e))
# mendaftarkan direktori pada sys.path
sys.path.insert(0, str(direktori))
import salam
print(salam.PENYAPA)gagal: No module named 'salam'
modul salam dieksekusi
Halo dari modul salamKeluaran tersebut menunjukkan tiga kejadian berurutan. Sebelum jalurnya terdaftar, pernyataan import ditolak dengan error ModuleNotFoundError. Setelah sys.path.insert mendaftarkan direktorinya, impor berhasil dan isi modul dieksekusi, yang terlihat dari cetakan modul salam dieksekusi. Variabel PENYAPA yang didefinisikan di tingkat atas modul kemudian dibaca sebagai atribut salam.PENYAPA.
Pola penulisan modul ke direktori sementara disertai pendaftaran jalurnya dipakai pada contoh-contoh topik ini agar setiap blok kode berdiri sendiri. Pada proyek sungguhan, direktori proyek biasanya sudah terdaftar secara alami karena Python mendaftarkan direktori skrip yang dijalankan.
Urutan pencarian modul#
sys.path adalah list berisi string direktori yang ditelusuri secara berurutan setiap kali ada pernyataan import. Python memeriksa satu per satu direktori pada list itu, berhenti pada kecocokan pertama, dan menimbulkan ModuleNotFoundError bila seluruh daftar telah habis tanpa hasil. Urutan penelusurannya digambarkan pada diagram berikut.
Tiga sumber pertama yang diperiksa adalah direktori tempat skrip berada, isi PYTHONPATH, lalu direktori site-packages tempat pip memasang package. Posisi terdepan direktori skrip menjelaskan mengapa modul yang ditulis di samping program selalu dapat diimpor tanpa pengaturan tambahan. Isi sys.path sendiri dapat diperiksa dari dalam program, dan contoh berikut hanya menampilkan bagian yang nilainya tidak bergantung pada mesin.
import sys
print(type(sys.path).__name__)
print(any("site-packages" in jalur for jalur in sys.path))list
TrueNilai True pada baris kedua berarti salah satu anggota sys.path mengandung direktori site-packages, yaitu tempat package pihak ketiga berada. Jalur lengkapnya sengaja tidak dicetak karena isinya berbeda pada setiap pemasangan, tetapi kehadirannya selalu dapat diuji seperti di atas.
Modul dieksekusi sekali per proses#
Import bukan pemanggilan ulang. Sebuah modul dieksekusi penuh hanya pada impor pertamanya, dan hasilnya disimpan pada dictionary sys.modules yang memetakan nama modul ke objek modulnya. Impor berikutnya pada proses yang sama cukup membaca dari cache tersebut, yaitu penyimpanan sementara di dalam memori, sehingga isi modul tidak dijalankan lagi.
import sys
import tempfile
from pathlib import Path
direktori = Path(tempfile.mkdtemp(prefix="contoh-modul-"))
(direktori / "salam.py").write_text(
'PENYAPA = "Halo dari modul salam"\n'
'print("modul salam dieksekusi")\n',
encoding="utf-8",
)
sys.path.insert(0, str(direktori))
import salam
import salam # sudah ada di sys.modules, diabaikan
print(salam.PENYAPA)
print("salam" in sys.modules)modul salam dieksekusi
Halo dari modul salam
TrueModul contoh memuat print pada tingkat atas, dan cetakan itu hanya muncul satu kali meskipun pernyataan import salam ditulis dua kali. Sifat ini menjadikan modul tempat yang tepat untuk keadaan yang perlu dijaga sepanjang program, misalnya konfigurasi yang dibaca sekali lalu dipakai bersama. Konsekuensinya, menyegarkan data dengan mengimpor ulang tidak berfungsi, dan perbaikannya adalah memanggil ulang fungsi yang ada di dalam modul tersebut.
Idiom if name == “main”#
Setiap modul membawa atribut __name__. Nilai atribut __name__ bernilai __main__ ketika berkas dijalankan langsung oleh interpreter dan bernilai nama modul itu sendiri ketika berkas diimpor. Idiom if __name__ == "__main__" memanfaatkan perbedaan itu untuk menaruh kode yang hanya berjalan pada mode skrip, misalnya pembacaan argumen baris perintah, sehingga satu berkas dapat berfungsi ganda sebagai pustaka dan sebagai program.
import subprocess
import sys
import tempfile
from pathlib import Path
direktori = Path(tempfile.mkdtemp(prefix="contoh-main-"))
skrip = direktori / "konversi.py"
skrip.write_text(
'def celsius_ke_fahrenheit(celsius):\n'
' return celsius * 9 / 5 + 32\n'
'\n'
'print(__name__)\n'
'\n'
'if __name__ == "__main__":\n'
' print(celsius_ke_fahrenheit(25))\n',
encoding="utf-8",
)
sys.path.insert(0, str(direktori))
# peran pertama, diimpor sebagai modul
import konversi
print("impor selesai")
# peran kedua, dijalankan langsung oleh interpreter baru
hasil = subprocess.run([sys.executable, str(skrip)], capture_output=True, text=True)
print(hasil.stdout, end="")konversi
impor selesai
__main__
77.0Dua baris pertama keluaran berasal dari proses utama. Saat diimpor, __name__ bernilai konversi, dan blok if dilewati sehingga baris konversi tidak dicetak. Dua baris terakhir berasal dari proses baru yang menjalankan berkas yang sama sebagai skrip. Pada proses itu, __name__ bernilai __main__ dan fungsi konversi akhirnya dipanggil. Pola ini menjelaskan mengapa banyak berkas pustaka dapat diamankan untuk diimpor tanpa efek samping yang tidak diinginkan.
Kesalahan umum#
Kesalahan pertama adalah memberi nama berkas yang sama dengan modul pustaka standar. Contoh berikut menulis statistics.py salinan tiruan, lalu mengimpornya.
import sys
import tempfile
from pathlib import Path
direktori = Path(tempfile.mkdtemp(prefix="contoh-timpa-"))
(direktori / "statistics.py").write_text(
'print("ini salinan lokal, bukan pustaka standar")\n',
encoding="utf-8",
)
sys.path.insert(0, str(direktori))
import statisticsini salinan lokal, bukan pustaka standarPustaka standar tidak pernah dimuat karena direktori tempat berkasnya berada diperiksa lebih dahulu, dan seluruh program yang mengandalkan fungsi statistik pun ikut rusak. Perbaikannya adalah mengganti nama berkas menjadi sesuatu yang tidak bentrok, misalnya rekap_statistik.py, lalu menghapus folder __pycache__ bila ada agar sisa hasil kompilasi tidak membingungkan.
Kesalahan kedua adalah menganggap impor ulang sebagai cara menyegarkan data. Seperti dibahas pada bagian sebelumnya, modul hanya dieksekusi sekali per proses, sehingga perubahan isi berkasnya tidak terlihat oleh program yang sedang berjalan. Cara yang benar adalah membungkus data yang berubah ke dalam fungsi, lalu memanggil fungsi itu setiap kali nilai terbaru dibutuhkan.
Kesalahan ketiga adalah menyebarkan sys.path.insert di banyak berkas untuk memaksa impor berhasil. Suntingan seperti itu sulit dilacak dan mudah saling menimpa. Kode yang saling membutuhkan dari arah yang berlawanan sebaiknya disusun ulang menjadi package, sehingga satu titik masuk yang terletak di luar package cukup untuk menjalankan seluruh program.
Ringkasan#
- Pernyataan import mengeksekusi berkas modul satu kali per proses dan mengikat objek modulnya pada
sys.modules, sehingga impor berikutnya tidak menjalankan ulang apa pun. - Python menelusuri
sys.pathsecara berurutan dari direktori skrip, isiPYTHONPATH, hinggasite-packages, dan berhenti pada kecocokan pertama. __name__bernilai__main__ketika berkas dijalankan langsung dan bernilai nama modulnya ketika diimpor, sehingga blokif __name__ == "__main__"hanya berjalan pada mode skrip.- Pendaftaran direktori melalui
sys.path.inserttepat untuk eksperimen sesaat, sedangkan kode yang saling membutuhkan diatur sebagai package.
Referensi#
- Modules — Python Software Foundation — Bagian tutorial resmi tentang modul, eksekusi sebagai skrip, dan jalur pencarian modul.
- The import system — Python Software Foundation
— Referensi lengkap mekanisme import dan penelusuran
sys.path. - sys — System-specific parameters and functions — Python Software Foundation
— Dokumentasi
sys.pathdansys.modulesyang dipakai pada topik ini. - main — Top-level code environment — Python Software Foundation
— Penjelasan resmi nilai
__name__pada mode skrip dan mode impor.