Topik ini menjelaskan apa yang terjadi ketika program Python dijalankan, dari kode sumber hingga instruksi yang dieksekusi mesin. Pemahaman alur ini menjelaskan beberapa hal yang ditemui secara langsung pada latihan berikutnya, seperti keberadaan direktori __pycache__ dan kebutuhan memasang pustaka tambahan. Pembahasan ditutup dengan pengenalan REPL sebagai mode interaktif untuk mencoba kode dengan cepat.
Bahasa yang diinterpretasikan#
Python termasuk bahasa yang diinterpretasikan (interpreted), yaitu bahasa yang kode sumbernya dijalankan langsung oleh sebuah program bernama interpreter. Interpreter membaca berkas .py, lalu mengerjakannya secara bertahap. Model ini berbeda dengan bahasa seperti C, yang kode sumbernya harus dikompilasi lebih dahulu menjadi berkas biner yang khusus untuk satu sistem operasi dan satu arsitektur prosesor. Pada C, berkas biner itulah yang didistribusikan dan dijalankan, sedangkan kode sumber tidak lagi dibutuhkan saat program berjalan.
Konsekuensi model interpretasi terasa pada beberapa hal praktis. Kode sumber Python yang sama dapat dijalankan di Windows, macOS, dan Linux tanpa perubahan, sepanjang masing-masing sistem memiliki interpreter. Langkah pembuatan biner yang terpisah tidak ada, sehingga jarak antara menulis kode dan menjalankannya menjadi pendek. Di sisi lain, penyebaran program Python umumnya berarti menyebarluaskan kode sumbernya, bukan berkas biner, karena interpreterlah yang menjalankan program tersebut.
Perlu ditegaskan bahwa “diinterpretasikan” tidak berarti Python membaca teks mentah baris demi baris setiap kali program berjalan. Interpreter tetap mengompilasi kode sumber terlebih dahulu, tetapi langkah itu terjadi di dalam interpreter dan tanpa perintah tambahan. Hasil kompilasinya bukan biner seperti milik C, melainkan bytecode, yaitu deretan instruksi sederhana yang dibaca dan dijalankan oleh CPython.
Dari kode sumber ke bytecode#
Mesin virtual Python adalah komponen CPython yang tugasnya mengeksekusi instruksi bytecode satu per satu. Ketika sebuah berkas program dijalankan, CPython membaca kode sumber, mengompilasinya menjadi bytecode, lalu mengeksekusi bytecode tersebut. Untuk berkas yang dijalankan langsung, hasil kompilasi tidak disimpan. Untuk modul yang diimpor, hasil kompilasi disimpan sebagai cache agar pemuatan berikutnya tidak perlu mengompilasi ulang.
Cache tersebut dapat diamati langsung. Buat sebuah modul kecil, lalu kompilasi dengan modul py_compile melalui perintah berikut.
# membuat contoh modul kecil di /tmp
mkdir -p /tmp/demo-bytecode
printf "def sapa():\n return 'Hai'\n" > /tmp/demo-bytecode/modul.py
# mengompilasi modul menjadi bytecode
python3 -m py_compile /tmp/demo-bytecode/modul.py
# melihat isi direktori __pycache__ yang muncul
ls /tmp/demo-bytecode/__pycache__
# membersihkan contoh
rm -rf /tmp/demo-bytecodemodul.cpython-312.pycBerkas modul.cpython-312.pyc muncul di dalam direktori __pycache__. Namanya tersusun dari nama modul, tag implementasi beserta versinya (cpython-312), dan akhiran .pyc. Ketika modul yang sama diimpor pada sesi Python berikutnya, CPython memeriksa cache ini dan memakainya tanpa mengompilasi ulang. Berkas .pyc bukan biner native seperti hasil kompilasi bahasa C, dan bukan pula bytecode JVM yang dieksekusi mesin virtual Java. Isinya hanya berlaku untuk mesin virtual milik implementasi yang membuatnya, sehingga program Python tidak pernah berdiri sendiri tanpa interpreter.
Instruksi bytecode itu sendiri dapat dilihat dengan modul dis, yaitu pembongkar bytecode bawaan Python.
import dis
kode = compile("harga * jumlah", "<contoh>", "eval")
dis.dis(kode) 0 0 RESUME 0
1 2 LOAD_NAME 0 (harga)
4 LOAD_NAME 1 (jumlah)
6 BINARY_OP 5 (*)
10 RETURN_VALUEFungsi compile mengubah satu ekspresi menjadi objek bytecode, dan dis.dis menampilkannya sebagai daftar instruksi. Instruksi LOAD_NAME mengambil nilai variabel, BINARY_OP melakukan perkalian, dan RETURN_VALUE menyerahkan hasilnya. Angka pada kolom kiri menunjukkan baris kode sumber dan posisi instruksi, sedangkan angka di dalam kurung adalah nama variabel yang bersangkutan. Satu ekspresi perkalian sederhana ternyata dieksekusi sebagai beberapa instruksi kecil, dan pekerjaan menjalankan instruksi itu dilakukan mesin virtual secara berurutan.
CPython dan implementasi lain#
Implementasi Python yang menjadi acuan bernama CPython, yaitu interpreter yang ditulis dalam bahasa C dan dikembangkan di repositori resmi Python. Nama CPython diambil dari bahasa C yang dipakai menulisnya. Interpreter inilah yang diunduh dari python.org, yang dijalankan dengan perintah python3, dan yang menjadi target hampir seluruh dokumentasi serta pustaka Python. Dokumentasi resmi Python pun umumnya menggambarkan perilaku CPython.
CPython bukan satu-satunya implementasi. PyPy adalah interpreter alternatif yang dilengkapi kompilasi saat berjalan (just-in-time compilation) untuk mempercepat program tertentu, sedangkan MicroPython adalah implementasi ringkas untuk mikrokontroler dengan sumber daya kecil. Seluruh implementasi menargetkan bahasa Python yang sama, tetapi bytecode-nya tidak saling cocok karena setiap implementasi memiliki mesin virtual dan format instruksinya sendiri. Inilah yang membedakan Python dari Java, yang bytecode-nya dirancang untuk satu mesin virtual yang sama, yaitu JVM.
Identitas implementasi yang sedang berjalan dapat diperiksa dari dalam Python dengan modul platform.
import platform
print(platform.python_implementation())
print(platform.python_version())CPython
3.12.16Fungsi platform.python_implementation() menampilkan nama implementasi, sedangkan platform.python_version() menampilkan versinya. Pada lingkungan latihan ini, keduanya menunjukkan CPython versi 3.12.16. Pemeriksaan semacam ini berguna ketika perilaku sebuah program perlu dicocokkan dengan implementasi dan versi tertentu.
REPL sebagai mental model#
Python juga dapat dijalankan tanpa berkas sama sekali. Mode ini disebut REPL (Read-Eval-Print Loop), yaitu perulangan yang membaca satu ekspresi, mengevaluasinya, mencetak hasilnya, lalu membaca ekspresi berikutnya. REPL dibuka dengan menjalankan python3 tanpa argumen, dan perulangannya ditandai dengan tanda >>> pada awal baris. Transkrip berikut memperlihatkan beberapa percobaan yang dilakukan di dalam REPL.
>>> 2 + 3
5
>>> "ha" * 3
'hahaha'
>>> luas = 7 * 6
>>> luas
42
>>> 5 + "lima"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'Transkrip di atas memperlihatkan perilaku dasar REPL. Ekspresi 2 + 3 langsung dijawab dengan hasilnya, yaitu 5. Operator * pada string mengulang isinya, sehingga "ha" * 3 menghasilkan ‘hahaha’. Pemberian nilai pada variabel luas tidak mencetak apa pun, dan mengetik luas sesudahnya menampilkan nilai 42. Ekspresi terakhir memunculkan error bertipe TypeError karena operator + tidak dapat menggabungkan angka dengan string, dan pesan errornya menjelaskan hal itu secara lengkap.
REPL berperan sebagai mental model, karena alur baca, evaluasi, cetak itulah pekerjaan dasar interpreter pada setiap baris program. Perbedaannya, pada skrip hasil evaluasi hanya tampil bila diminta lewat print, sedangkan REPL selalu menampilkan hasil ekspresi yang diketik. Program utuh tetap ditulis pada berkas .py dan dijalankan dengan python3 nama_berkas.py, sedangkan REPL dipakai untuk menguji potongan perilaku sebelum dipindahkan ke program.
Ringkasan#
- CPython mengompilasi kode sumber menjadi bytecode, lalu mengeksekusinya di mesin virtualnya tanpa langkah kompilasi yang diperintahkan sendiri.
- Hasil kompilasi modul yang diimpor disimpan sebagai berkas
.pycdi dalam__pycache__, dan berkas tersebut dibuat ulang otomatis bila dihapus. - Instruksi bytecode dapat diperiksa dengan modul
dis, sedangkan identitas implementasi dan versinya dapat diperiksa dengan modulplatform. - REPL membaca satu ekspresi lalu mencetak hasilnya secara berulang, sehingga cocok untuk eksperimen kecil, sedangkan program utuh dijalankan sebagai berkas skrip.
Referensi#
- The Python Tutorial: Using the Python Interpreter — Python Software Foundation — Dokumentasi resmi cara menjalankan Python, baik sebagai skrip maupun melalui REPL.
- dis — Disassembler for Python bytecode — Python Software Foundation
— Dokumentasi modul
disuntuk memeriksa instruksi bytecode. - platform — Access to underlying platform’s identifying data — Python Software Foundation
— Dokumentasi fungsi
python_implementation()danpython_version()yang dipakai pada contoh.