Apakah layak untuk mengompilasi Python ke kode mesin?

128

Seberapa layak mengkompilasi Python (mungkin melalui representasi C menengah) ke dalam kode mesin?

Mungkin perlu menautkan ke pustaka runtime Python, dan setiap bagian dari pustaka standar Python yang merupakan Python sendiri juga perlu dikompilasi (dan ditautkan).

Selain itu, Anda perlu mengelompokkan interpreter Python jika Anda ingin melakukan evaluasi ekspresi yang dinamis, tetapi mungkin sebagian dari Python yang tidak mengizinkan ini masih berguna.

Apakah akan memberikan keuntungan penggunaan kecepatan dan / atau memori? Agaknya waktu startup interpreter Python akan dihilangkan (meskipun perpustakaan bersama masih perlu memuat saat startup).

Andy Balaam
sumber
2
Btw, pertanyaan Anda akan menjadi IMHO lebih jelas jika Anda meminta "kode mesin" daripada kode objek.
Torsten Marek

Jawaban:

31

Coba kompiler ShedSkin Python-to-C ++, tetapi jauh dari sempurna. Juga ada Psyco - Python JIT jika hanya diperlukan speedup. Tapi IMHO ini tidak sepadan dengan usaha. Untuk bagian kode yang kritis terhadap kecepatan, solusi terbaik adalah menuliskannya sebagai ekstensi C / C ++.

cleg
sumber
5
FYI, ShedSkin menjatuhkan dukungan Windows.
Sorin
2
@sorin: yah, hari ini mendukung windows ... code.google.com/p/shedskin/downloads/…
2
Solusi terbaik, dengan cepat, masih bisa PyPy .
Cees Timmerman
kulit rajutan tidak memiliki pekerjaan dalam sekitar dua tahun sekarang. :(
Perkins
53

Seperti yang dikatakan @Greg Hewgill, ada alasan bagus mengapa ini tidak selalu mungkin. Namun, beberapa jenis kode (seperti kode yang sangat algoritmik) dapat diubah menjadi kode mesin "nyata".

Ada beberapa opsi:

  • Gunakan Psyco , yang memancarkan kode mesin secara dinamis. Anda harus memilih dengan hati-hati metode / fungsi mana yang akan dikonversi.
  • Gunakan Cython , yang merupakan bahasa mirip -Python yang dikompilasi menjadi ekstensi Python C
  • Gunakan PyPy , yang memiliki penerjemah dari RPython ( subset terbatas dari Python yang tidak mendukung beberapa fitur Python yang paling "dinamis") ke C atau LLVM.
    • PyPy masih sangat eksperimental
    • tidak semua ekstensi akan ada

Setelah itu, Anda dapat menggunakan salah satu paket yang ada (membekukan, Py2exe, PyInstaller) untuk meletakkan semuanya menjadi satu biner.

Semua dalam semua: tidak ada jawaban umum untuk pertanyaan Anda. Jika Anda memiliki kode Python yang sangat kritis terhadap kinerja, coba gunakan sebanyak mungkin fungsi builtin (atau tanyakan pertanyaan "Bagaimana cara membuat kode Python saya lebih cepat"). Jika itu tidak membantu, cobalah untuk mengidentifikasi kode dan port ke C (atau Cython) dan gunakan ekstensi.

Torsten Marek
sumber
3
Pypy adalah penerus Psyco
bcattle
19

py2c ( https://github.com/pradyun/Py2C ) dapat mengkonversi kode python ke c / c ++ Saya adalah pengembang solo py2c.

Ramchandra Apte
sumber
Ini terlihat seperti alat yang berguna. Apakah masih dipertahankan?
Anderson Green
@AndersonGreen Ini masih dalam tahap pengembangan awal terakhir kali saya mengerjakannya (mungkin serupa sekarang). Saya sudah meninggalkan proyek karena saya ̶b̶u̶s̶y̶ saya malas. Jika Anda belum melihat teks "Penting", itu telah pindah ke GitHub sekarang.
Ramchandra Apte
Tautan menunjuk ke installer yang belum diselesaikan , yang tampaknya merupakan proyek yang berbeda. Apakah py2c masih tersedia di GitHub?
Anderson Green
@AndersonGreen Wow itu tidak diperhatikan begitu lama! Ini dia
Ramchandra Apte
Tautan pada code.google.com/p/py2c masih menunjuk ke installer yang belum diselesaikan, sehingga harus diperbarui sekarang.
Anderson Green
15

PyPy adalah proyek untuk mengimplementasikan kembali Python di Python, menggunakan kompilasi ke kode asli sebagai salah satu strategi implementasi (yang lain menjadi VM dengan JIT, menggunakan JVM, dll.). Versi C yang dikompilasi berjalan rata-rata lebih lambat daripada CPython tetapi jauh lebih cepat untuk beberapa program.

Shedskin adalah kompiler Python-to-C ++ eksperimental.

Pyrex adalah bahasa yang dirancang khusus untuk menulis modul ekstensi Python. Ini dirancang untuk menjembatani kesenjangan antara dunia Python yang bagus, tingkat tinggi, mudah digunakan dan dunia C. tingkat rendah yang berantakan.

pdc
sumber
3
Cython adalah fork ramah dari Pyrex yang lebih banyak digunakan dan dikembangkan secara lebih aktif.
Mike Graham
"dunia Python yang menyenangkan, tingkat tinggi, mudah digunakan dan dunia C tingkat rendah yang berantakan" - lucu, saya hanya memikirkan bagaimana C dan assembler "bagus" dan sederhana, dan Python hidup dalam " dunia "," tingkat tinggi "berantakan
Reversed Engineer
14

Nuitka adalah kompiler Python ke C ++ yang terhubung dengan libpython. Tampaknya menjadi proyek yang relatif baru. Penulis mengklaim peningkatan kecepatan dibandingkan CPython pada benchmark pystone.

bcattle
sumber
10

Ini mungkin tampak masuk akal pada pandangan pertama, namun ada banyak hal biasa di Python yang tidak langsung bisa dipetakan ke representasi C tanpa membawa lebih banyak dukungan runtime Python. Misalnya, mengetik bebek muncul di pikiran. Banyak fungsi dalam Python yang membaca input dapat mengambil file atau seperti file objek , asalkan mendukung operasi tertentu, misalnya. baca () atau readline (). Jika Anda berpikir tentang apa yang diperlukan untuk memetakan jenis dukungan ini ke C, Anda mulai membayangkan dengan tepat hal-hal yang sudah dilakukan sistem runtime Python.

Ada beberapa utilitas seperti py2exe yang akan membundel program Python dan runtime menjadi satu yang dapat dieksekusi (sejauh mungkin).

Greg Hewgill
sumber
1
Bagaimana jika tujuan saya adalah memastikan bahwa kode dikompilasi, karena bahasa yang dikompilasi secara statis (setidaknya menurut saya) lebih kecil kemungkinannya meledak pada saat run time? Apakah mungkin untuk menentukan bahwa beberapa foo.xungkapan tidak akan berfungsi karena footidak akan memiliki xpada saat dipanggil. Apakah ada checker kode statis untuk Python? Python dapat dikompilasi ke perakitan .Net ...
Hamish Grubijan
10

Pyrex adalah bagian dari bahasa Python yang mengkompilasi ke C, dilakukan oleh orang yang pertama kali membangun daftar pemahaman untuk Python. Ini terutama dikembangkan untuk membangun pembungkus tetapi dapat digunakan dalam konteks yang lebih umum. Cython adalah garpu pyrex yang dipelihara lebih aktif.

ConcernedOfTunbridgeWells
sumber
2
Cython adalah fork ramah dari Pyrex yang lebih banyak digunakan dan dikembangkan secara lebih aktif.
Mike Graham
3

Jython memiliki kompiler yang menargetkan bytecode JVM. Bytecode sepenuhnya dinamis, seperti bahasa Python itu sendiri! Sangat keren. (Ya, seperti disinggung oleh jawaban Greg Hewgill, bytecode menggunakan runtime Jython, dan karenanya file jar Jython harus didistribusikan dengan aplikasi Anda.)

Chris Jester-Young
sumber
2

Psyco adalah sejenis kompiler just-in-time (JIT): kompiler dinamis untuk Python, menjalankan kode 2-100 kali lebih cepat, tetapi membutuhkan banyak memori.

Singkatnya: ini menjalankan perangkat lunak Python Anda yang ada jauh lebih cepat, tanpa perubahan sumber Anda tetapi tidak mengkompilasi ke kode objek dengan cara yang sama seperti kompiler C.

Pierre-Jean Coudert
sumber
2

Jawabannya adalah "Ya, itu mungkin". Anda bisa mengambil kode Python dan mencoba mengkompilasinya menjadi kode C yang setara menggunakan API CPython. Bahkan, dulu ada proyek Python2C yang melakukan hal itu, tapi saya belum pernah mendengarnya selama bertahun-tahun (kembali dalam Python 1,5 hari adalah ketika saya terakhir melihatnya.)

Anda dapat mencoba menerjemahkan kode Python ke dalam bahasa C sebanyak mungkin, dan kembali ke API CPython saat Anda membutuhkan fitur Python yang sebenarnya. Saya telah mempermainkan ide itu sendiri satu atau dua bulan terakhir. Namun, ini merupakan pekerjaan yang sangat buruk, dan sejumlah besar fitur Python sangat sulit untuk diterjemahkan ke dalam C: fungsi bersarang, generator, apa pun kecuali kelas sederhana dengan metode sederhana, apa pun yang melibatkan memodifikasi modul global dari luar modul, dll. , dll.

Thomas Wouters
sumber
2

Ini tidak mengkompilasi Python ke kode mesin. Tetapi memungkinkan untuk membuat perpustakaan bersama untuk memanggil kode Python.

Jika apa yang Anda cari adalah cara mudah untuk menjalankan kode Python dari C tanpa mengandalkan hal-hal execp. Anda bisa menghasilkan pustaka bersama dari kode python yang dibungkus dengan beberapa panggilan ke API penyematan Python . Yah aplikasinya adalah shared library, sebuah .so yang dapat Anda gunakan di banyak perpustakaan / aplikasi lain.

Berikut adalah contoh sederhana yang membuat perpustakaan bersama, yang dapat Anda tautkan dengan program C. Pustaka bersama mengeksekusi kode Python.

File python yang akan dieksekusi adalah pythoncalledfromc.py:

# -*- encoding:utf-8 -*-
# this file must be named "pythoncalledfrom.py"

def main(string):  # args must a string
    print "python is called from c"
    print "string sent by «c» code is:"
    print string
    print "end of «c» code input"
    return 0xc0c4  # return something

Anda dapat mencobanya dengan python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). Ini akan menampilkan:

python is called from c
string sent by «c» code is:
HELLO
end of «c» code input

Pustaka bersama akan ditentukan oleh yang berikut dengan callpython.h:

#ifndef CALL_PYTHON
#define CALL_PYTHON

void callpython_init(void);
int callpython(char ** arguments);
void callpython_finalize(void);

#endif

Yang terkait callpython.cadalah:

// gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <python2.7/Python.h>

#include "callpython.h"

#define PYTHON_EXEC_STRING_LENGTH 52
#define PYTHON_EXEC_STRING "import pythoncalledfromc; pythoncalledfromc.main(\"%s\")"


void callpython_init(void) {
     Py_Initialize();
}

int callpython(char ** arguments) {
  int arguments_string_size = (int) strlen(*arguments);
  char * python_script_to_execute = malloc(arguments_string_size + PYTHON_EXEC_STRING_LENGTH);
  PyObject *__main__, *locals;
  PyObject * result = NULL;

  if (python_script_to_execute == NULL)
    return -1;

  __main__ = PyImport_AddModule("__main__");
  if (__main__ == NULL)
    return -1;

  locals = PyModule_GetDict(__main__);

  sprintf(python_script_to_execute, PYTHON_EXEC_STRING, *arguments);
  result = PyRun_String(python_script_to_execute, Py_file_input, locals, locals);
  if(result == NULL)
    return -1;
  return 0;
}

void callpython_finalize(void) {
  Py_Finalize();
}

Anda dapat mengompilasinya dengan perintah berikut:

gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

Buat file dengan nama callpythonfromc.cyang berisi yang berikut ini:

#include "callpython.h"

int main(void) {
  char * example = "HELLO";
  callpython_init();
  callpython(&example);
  callpython_finalize();
  return 0;
}

Kompilasi dan jalankan:

gcc callpythonfromc.c callpython.so -o callpythonfromc
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc

Ini adalah contoh yang sangat mendasar. Ini dapat bekerja, tetapi tergantung pada pustaka, mungkin masih sulit untuk membuat serialisasi struktur data C menjadi Python dan dari Python ke C. Hal-hal dapat diotomatisasi ...

Nuitka mungkin bisa membantu.

Juga ada numba tetapi mereka berdua tidak bertujuan untuk melakukan apa yang Anda inginkan. Menghasilkan header C dari kode Python dimungkinkan, tetapi hanya jika Anda menentukan cara mengkonversi tipe Python ke tipe C atau dapat menyimpulkan informasi itu. Lihat python astroid untuk penganalisis Python ast.

amirouche
sumber