Mengapa Python tidak membutuhkan kompiler?

29

Hanya ingin tahu (sekarang saya sudah mulai dengan C ++ yang membutuhkan kompiler) mengapa Python tidak membutuhkan kompiler?

Saya hanya memasukkan kode, menyimpannya sebagai eksekutif, dan menjalankannya. Di C ++ saya harus membuat build dan semua hal menyenangkan lainnya.

Billjk
sumber
4
Python hanyalah bahasa dengan banyak implementasi. Iron Python dikompilasi dengan cara yang sama dengan C # dan C ++ dikompilasi, dan mungkin ada implementasi lain seperti itu.
Pekerjaan
1
C # dan C ++ tidak dikompilasi dengan cara yang sama - meskipun Anda bisa berpendapat bahwa keduanya berakhir sebagai instruksi mesin pada akhirnya, tetapi jika Anda melakukannya maka Anda dapat mengatakan BASIC dikompilasi dengan cara yang sama juga.
gbjbaanb
7
@ gbjbaanb tetapi sekali lagi bahasa Inggris tidak dikompilasi dan analisis semantik dari satu kalimat dapat menghasilkan dua hasil yang sama-sama valid dan di atas dapat dibaca sebagai "python besi dikompilasi seperti C # dan C ++ dikompilasi"
Rune FS
Platform / perangkat lunak apa yang Anda gunakan untuk menulis kode Python Anda? Jika Anda menulis file .py, ini bukan file yang dapat dieksekusi. Ini masih merupakan file kode sumber. Dari baris perintah Anda menggunakan pythonperintah untuk menafsirkan file .py atau jika Anda menggunakan IDLE atau Eclipse, IDE akan melakukannya untuk Anda.
Rick Henderson

Jawaban:

68

Python memiliki kompiler! Anda hanya tidak menyadarinya karena itu berjalan secara otomatis. Anda dapat mengetahui bahwa file tersebut ada di sana: lihat file .pyc(atau .pyojika optimizer diaktifkan) yang dihasilkan untuk modul yang Anda inginkan import.

Juga, itu tidak dikompilasi dengan kode mesin asli. Sebagai gantinya, ia mengkompilasi ke kode byte yang digunakan oleh mesin virtual. Mesin virtual itu sendiri adalah program yang dikompilasi. Ini sangat mirip dengan cara kerja Java; sangat mirip, pada kenyataannya, bahwa ada varian Python ( Jython ) yang mengkompilasi ke kode byte Java Virtual Machine sebagai gantinya! Ada juga IronPython , yang mengkompilasi ke Microsoft CLR (digunakan oleh .NET). (Kompilator kode byte Python normal kadang-kadang disebut CPython untuk memisahkannya dari alternatif ini.)

C ++ perlu memaparkan proses kompilasi karena bahasa itu sendiri tidak lengkap; itu tidak menentukan semua yang perlu diketahui oleh penghubung untuk membangun program Anda, juga tidak dapat menentukan opsi kompilasi dengan mudah (beberapa kompiler memungkinkan Anda menggunakannya #pragma, tetapi itu bukan standar). Jadi, Anda harus melakukan sisa pekerjaan dengan makefiles dan mungkin auto hell (autoconf / automake / libtool). Ini benar-benar hanya peninggalan dari bagaimana C melakukannya. Dan C melakukannya dengan cara itu karena itu membuat kompiler sederhana, yang merupakan salah satu alasan utama itu begitu populer (siapa pun bisa membuat kompiler C sederhana di tahun 80-an).


Beberapa hal yang dapat memengaruhi operasi kompiler atau tautan tetapi tidak ditentukan dalam sintaks C atau C ++:

  • resolusi ketergantungan
  • persyaratan perpustakaan eksternal (termasuk urutan ketergantungan)
  • tingkat pengoptimal
  • pengaturan peringatan
  • versi spesifikasi bahasa
  • pemetaan tautan (bagian mana yang dituju dalam program akhir)
  • arsitektur target

Beberapa di antaranya dapat dideteksi, tetapi tidak dapat ditentukan; misalnya saya dapat mendeteksi C ++ mana yang digunakan __cplusplus, tetapi saya tidak dapat menentukan bahwa C ++ 98 adalah yang digunakan untuk kode saya di dalam kode itu sendiri; Saya harus meneruskannya sebagai flag ke compiler di Makefile, atau membuat pengaturan dalam dialog.

Meskipun Anda mungkin berpikir bahwa sistem "resolusi ketergantungan" ada di kompiler, secara otomatis menghasilkan catatan ketergantungan, catatan ini hanya mengatakan file header mana yang digunakan oleh file sumber yang diberikan. Mereka tidak dapat menunjukkan modul kode sumber tambahan apa yang diperlukan untuk menautkan ke program yang dapat dieksekusi, karena tidak ada cara standar dalam C atau C ++ untuk menunjukkan bahwa file header yang diberikan adalah definisi antarmuka untuk modul kode sumber lain sebagai lawan dari hanya sekelompok baris yang ingin Anda tunjukkan di banyak tempat sehingga Anda tidak mengulanginya. Ada tradisi dalam konvensi penamaan file, tetapi ini tidak dikenal atau dipaksakan oleh kompiler dan tautan.

Beberapa di antaranya dapat diatur menggunakan #pragma, tetapi ini non-standar, dan saya berbicara tentang standar. Semua hal ini dapat ditentukan oleh standar, tetapi belum untuk kepentingan kompatibilitas ke belakang. Kebijaksanaan yang berlaku adalah bahwa makefile dan IDE tidak rusak, jadi jangan memperbaikinya.

Python menangani semua ini dalam bahasa. Sebagai contoh, importmenentukan ketergantungan modul eksplisit, menyiratkan pohon ketergantungan, dan modul tidak dibagi menjadi file header dan sumber (yaitu antarmuka dan implementasi).

Mike DeSimone
sumber
3
Implementasi C dari Python adalah CPython , Cython adalah sesuatu yang berbeda.
Greg Hewgill
4
Alasan lain mengapa C dikompilasi ke kode mesin adalah bahwa itu dimaksudkan untuk menjadi sedikit lebih dari assembler yang dimuliakan, karena penerjemah bytecode secara teknis tidak layak pada perangkat keras yang mereka miliki, dan karena salah satu tugas paling penting adalah menulis kernel OS.
tdammers
2
@ BillyONeal dengan satu pengecualian besar bahwa dalam c / c ++ Anda sebagai programmer harus melakukan hal-hal dengan cara tertentu (baik membuat file atau membuang semua hal ke dalam gumpalan yang sama) dengan python Anda hanya melakukan pekerjaan Anda dan kompilator bersama dengan VM mengurus sisanya
Rune FS
3
"C ++ perlu memaparkan proses kompilasi karena bahasa itu sendiri tidak lengkap" Er, apa ??
Lightness Races dengan Monica
3
Anda membaca bagian setelah itu , kan? "itu tidak menentukan semua yang perlu diketahui oleh penghubung untuk membangun program Anda, juga tidak dapat menentukan opsi kompilasi yang mudah dibawa." Anda tidak bisa hanya membangun saja C ++ file dengan makan ke kompilator; sering kali Anda harus memberikan metadata seperti flag kompilasi, termasuk path, dll. Metadata ini tidak ditentukan oleh standar dan tidak portabel, itulah sebabnya kami harus menyeret hal-hal lain seperti make, cmake, Visual Studio, atau apa pun untuk selesaikan pekerjaan. Jadi standar harus memanggil beberapa hal seperti di unit kompilasi dan yang lainnya sebagai program-lebar.
Mike DeSimone
7

Python adalah bahasa yang ditafsirkan. Ini berarti ada perangkat lunak di komputer Anda yang membaca kode Python, dan mengirimkan "instruksi" ke mesin. The artikel Wikipedia pada bahasa ditafsirkan mungkin menarik.

Ketika bahasa seperti C ++ (bahasa yang dikompilasi) dikompilasi, itu berarti bahwa itu dikonversi menjadi kode mesin untuk dibaca langsung oleh perangkat keras ketika dieksekusi. The artikel Wikipedia pada bahasa dikompilasi mungkin memberikan kontras yang menarik.

Zenon
sumber
21
Tidak ada bahasa yang ditafsirkan atau dikompilasi. Bahasa adalah seperangkat aturan matematika yang abstrak. Bahasa tidak dikompilasi atau ditafsirkan. Bahasa apa adanya . Kompilasi dan interpretasi adalah sifat dari kompiler atau juru bahasa (duh!), Bukan bahasa. Setiap bahasa dapat diimplementasikan dengan kompiler dan setiap bahasa dapat diimplementasikan dengan penerjemah. Sebagian besar bahasa memiliki implementasi dan interpretasi yang ditafsirkan. Ada interpreter untuk C ++ dan ada kompiler untuk Python. (Faktanya, semua implementasi Python yang ada saat ini memiliki kompiler.)
Jörg W Mittag
4
Mayoritas implementasi bahasa modern berkinerja tinggi menggabungkan baik juru bahasa dan kompiler (atau bahkan beberapa kompiler) untuk kinerja maksimum. Sebenarnya, tidak mungkin menjalankan program apa pun tanpa juru bahasa. Bagaimanapun, kompiler hanyalah sebuah program yang menerjemahkan suatu program dari satu bahasa ke bahasa lain. Tetapi pada beberapa titik Anda harus benar-benar menjalankan program, yang dilakukan oleh seorang penerjemah (yang mungkin atau mungkin tidak diimplementasikan dalam silikon).
Jörg W Mittag
10
@ JörgWMittag: Secara teknis Anda benar. Namun, sebagian besar bahasa dirancang untuk konteks yang ditafsirkan atau untuk kompilasi penuh. Menulis penerjemah untuk GW BASIC atau Common Lisp jauh lebih mudah daripada menulis satu untuk, katakanlah, C ++ atau C #; Python kehilangan banyak nilai jualnya tanpa lingkungan interaktif; menulis kompiler untuk PHP sangat sulit, dan mungkin sangat tidak efisien, karena executable yang dikompilasi harus mengandung seluruh interpreter PHP, karena eval () dan konstruksi yang serupa - orang dapat berpendapat bahwa kompiler seperti itu akan curang.
tdammers
2
@Dammers, ya. Kita dapat menggunakan "bahasa yang dikompilasi" secara wajar untuk berarti "bahasa yang biasanya dikompilasi." Tapi itu merindukan titik bahwa PHP, Java, Python, Lua, dan C # semuanya diimplementasikan sebagai kompiler untuk bytecode. Semua bahasa ini juga telah menerapkan JIT untuk mereka. Jadi sungguh, Anda tidak dapat benar-benar memanggil beberapa bahasa ini dikompilasi dan beberapa ditafsirkan karena mereka punya strategi implementasi yang sama.
Winston Ewert
2
@ Billyilly, setidaknya tidak benar untuk python. Anda dapat mendistribusikan bytecode python dan menjalankannya tanpa sumber. Tetapi benar bahwa Anda tidak dapat mendistribusikan python tanpa kompiler.
Winston Ewert
5

Tidak semua bahasa yang dikompilasi memiliki siklus edit-kompilasi-tautan-lari di-wajah Anda.

Apa yang Anda hadapi adalah fitur / batasan C ++ (atau setidaknya implementasi C ++).

Untuk melakukan apa pun, Anda harus menyimpan kode Anda ke dalam file, dan membangun gambar monolitik dengan proses yang disebut tautan.

Secara khusus, ini proses menghubungkan monolitik yang keliru untuk perbedaan antara kompilasi dan interpretasi.

Beberapa bahasa melakukan semua hal ini secara lebih dinamis, dengan menghilangkan langkah penghubung monolitik yang kikuk, bukan dengan menghilangkan kompilasi ke kode mesin. Sumber masih dikompilasi ke file objek, tetapi ini dimuat ke dalam run-time image, daripada dihubungkan ke executable monolitik.

Anda mengatakan "memuat kembali modul ini", dan memuat sumber dan menginterpretasinya, atau mengkompilasinya, tergantung pada beberapa mode switch.

Pemrograman kernel Linux memiliki beberapa rasa ini meskipun Anda bekerja di C. Anda dapat mengkompilasi ulang modul dan memuat dan membongkar itu. Tentu saja, Anda masih sadar bahwa Anda menghasilkan beberapa hal yang dapat dieksekusi, dan dikelola oleh sistem build yang kompleks, dengan masih beberapa langkah manual. Tetapi kenyataannya adalah bahwa pada akhirnya Anda dapat membongkar dan memuat ulang hanya modul kecil itu dan tidak harus me-restart seluruh kernel.

Beberapa bahasa memiliki modularisasi berbutir lebih halus daripada ini, dan pembangunan dan pemuatan dilakukan dari dalam waktu run-time, sehingga lebih mulus.

Kaz
sumber
2

apa pengalihan dari pertanyaan awal ... Suatu hal yang tidak disebutkan adalah bahwa sumber program python adalah apa yang Anda gunakan dan distribusikan, dari perspektif pengguna itu adalah program. Kami cenderung menyederhanakan hal-hal ke dalam kategori yang tidak didefinisikan dengan baik.

Program yang dikompilasi biasanya dianggap sebagai file kode mesin yang berdiri sendiri. (diakui sering mengandung tautan ke pustaka tautan dinamis yang terkait dengan sistem operasi tertentu). Ini mengatakan ... ada variasi dari sebagian besar bahasa pemrograman yang dapat digambarkan sebagai dikompilasi atau ditafsirkan.

Python tidak memerlukan kompiler karena bergantung pada aplikasi (disebut interpreter) yang mengkompilasi dan menjalankan kode tanpa menyimpan kode mesin yang dibuat dalam bentuk yang Anda dapat dengan mudah mengakses atau mendistribusikan.

Stephen Robinson
sumber
1

Semua bahasa pemrograman membutuhkan terjemahan dari konsep manusia ke dalam kode mesin target. Bahkan bahasa assembly harus diterjemahkan ke dalam kode mesin. Terjemahan itu biasanya terjadi dalam fase-fase berikut:

Fase 1: Analisis dan terjemahan (parsing) menjadi kode perantara. Fase 2: Penerjemahan kode perantara ke kode mesin target dengan penampung untuk referensi eksternal. Fase 3: Resolusi referensi eksternal dan pengemasan ke dalam program yang dapat dieksekusi mesin.

Terjemahan ini sering disebut sebagai pra-kompilasi dan "Just in time" (JIT) atau run-time-compiling.

Bahasa seperti C, C ++, COBOL, Fortran, Pascal (tidak semua) dan Assembly adalah bahasa yang dikompilasi yang dapat dieksekusi secara langsung oleh sistem operasi tanpa perlu juru bahasa.

Bahasa seperti Java, BASIC, C # dan Python diinterpretasikan. Mereka semua menggunakan kode perantara yang dibuat dalam Fase 1, tetapi kadang-kadang akan berbeda dalam bagaimana mereka menerjemahkannya ke dalam kode mesin. Bentuk paling sederhana menggunakan kode perantara untuk menjalankan rutinitas kode mesin yang melakukan pekerjaan yang diharapkan. Orang lain akan mengkompilasi kode antara ke kode mesin dan melakukan memperbaiki ketergantungan eksternal selama runtime. Setelah dikompilasi dapat langsung dieksekusi. Kode mesin juga disimpan dalam cache dari kode mesin yang dapat digunakan kembali yang sebelumnya dikompilasi yang nantinya dapat digunakan kembali jika fungsi tersebut diperlukan lagi nanti. Jika suatu fungsi telah di-cache, interpreter tidak perlu mengkompilasinya lagi.

Sebagian besar bahasa tingkat tinggi modern termasuk dalam kategori ditafsirkan (dengan JIT). Sebagian besar bahasa yang lebih tua seperti C & C ++ yang dikompilasi.

Mark Baker
sumber