Có khả thi để biên dịch Python thành mã máy không?


127

Làm thế nào khả thi để biên dịch Python (có thể thông qua biểu diễn C trung gian) thành mã máy?

Có lẽ nó sẽ cần liên kết đến thư viện thời gian chạy Python và bất kỳ phần nào của thư viện chuẩn Python mà chính Python cũng cần phải được biên dịch (và liên kết trong).

Ngoài ra, bạn sẽ cần phải đóng gói trình thông dịch Python nếu bạn muốn thực hiện đánh giá động các biểu thức, nhưng có lẽ một tập hợp con Python không cho phép điều này vẫn hữu ích.

Nó sẽ cung cấp bất kỳ lợi thế về tốc độ và / hoặc sử dụng bộ nhớ? Có lẽ thời gian khởi động của trình thông dịch Python sẽ bị loại bỏ (mặc dù các thư viện dùng chung vẫn cần tải khi khởi động).


2
Btw, câu hỏi của bạn sẽ IMHO rõ ràng hơn nếu bạn hỏi "mã máy" chứ không phải mã đối tượng.
Torsten Marek

Câu trả lời:


31

Hãy dùng thử trình biên dịch Python-to-C ++ của ShedSkin , nhưng nó không hoàn hảo. Ngoài ra còn có Psyco - Python JIT nếu chỉ cần tăng tốc. Nhưng IMHO điều này không đáng để nỗ lực. Đối với các phần quan trọng về tốc độ, giải pháp tốt nhất sẽ là viết chúng dưới dạng các phần mở rộng C / C ++.


5
FYI, ShedSkin bỏ hỗ trợ Windows.
sorin

2
@sorin: tốt, hôm nay nó hỗ trợ các cửa sổ ... code.google.com/p/shed

2
Giải pháp tốt nhất, nhanh chóng, vẫn có thể là PyPy .
Cees Timmerman

shed leather đã không có công việc được thực hiện trên nó trong khoảng hai năm nay. :(
Perkins

53

Như @Greg Hewgill nói, có những lý do chính đáng tại sao điều này không phải lúc nào cũng có thể. Tuy nhiên, một số loại mã nhất định (như mã rất thuật toán) có thể được chuyển thành mã máy "thực".

Có một số lựa chọn:

  • Sử dụng Psyco , phát ra mã máy một cách linh hoạt. Bạn nên chọn cẩn thận những phương thức / chức năng để chuyển đổi, mặc dù.
  • Sử dụng Cython , một ngôn ngữ giống như Python được biên dịch thành phần mở rộng Python C
  • Sử dụng PyPy , có trình dịch từ RPython (một tập hợp con bị hạn chế của Python không hỗ trợ một số tính năng "động" nhất của Python) sang C hoặc LLVM.
    • PyPy vẫn còn nhiều thử nghiệm
    • không phải tất cả các phần mở rộng sẽ có mặt

Sau đó, bạn có thể sử dụng một trong các gói hiện có (đóng băng, Py2exe, PyInstaller) để đặt mọi thứ vào một nhị phân.

Tất cả trong tất cả: không có câu trả lời chung cho câu hỏi của bạn. Nếu bạn có mã Python quan trọng về hiệu năng, hãy thử sử dụng càng nhiều chức năng dựng sẵn càng tốt (hoặc hỏi câu hỏi "Làm cách nào để làm cho mã Python của tôi nhanh hơn"). Nếu điều đó không có ích, hãy thử xác định mã và chuyển mã sang C (hoặc Cython) và sử dụng tiện ích mở rộng.


3
Pypy là sự kế thừa của Psyco
bcattle

19

py2c ( https://github.com/pradyun/Py2C ) có thể chuyển đổi mã python thành c / c ++ Tôi là nhà phát triển solo của py2c.


Đây trông giống như một công cụ hữu ích. Nó vẫn đang được duy trì?
Anderson Green

@AndersonGreen Đó là trong giai đoạn phát triển ban đầu, lần cuối cùng tôi làm việc với nó (có lẽ tương tự như bây giờ). Tôi đã rời khỏi dự án bởi vì tôi lười biếng. Nếu bạn chưa nhận thấy văn bản "Quan trọng", nó đã chuyển sang GitHub ngay bây giờ.
Ramowderra Apte

Liên kết trỏ đến trình cài đặt unvanquished , dường như là một dự án khác. Py2c vẫn có sẵn trên GitHub chứ?
Anderson Green

@AndersonGreen Wow mà không được chú ý quá lâu! Bạn đi đây
Ramowderra Apte

Liên kết trên code.google.com/p/py2c vẫn trỏ đến trình cài đặt chưa được yêu cầu, vì vậy nó cần được cập nhật ngay bây giờ.
Anderson Green

15

PyPy là một dự án để thực hiện lại Python trong Python, sử dụng biên dịch thành mã gốc làm một trong những chiến lược triển khai (các chiến lược khác là VM với JIT, sử dụng JVM, v.v.). Các phiên bản C được biên dịch của họ chạy chậm hơn CPython trung bình nhưng nhanh hơn nhiều đối với một số chương trình.

Shed leather là một trình biên dịch Python-to-C ++ thử nghiệm.

Pyrex là một ngôn ngữ được thiết kế đặc biệt để viết các mô-đun mở rộng Python. Nó được thiết kế để thu hẹp khoảng cách giữa thế giới Python đẹp, cấp cao, dễ sử dụng và thế giới cấp thấp, lộn xộn của C.


3
Cython là một ngã ba thân thiện được sử dụng rộng rãi hơn, được phát triển tích cực hơn của Pyrex.
Mike Graham

"thế giới tốt đẹp, cấp cao, dễ sử dụng của Python và thế giới C cấp thấp, lộn xộn" - buồn cười tôi chỉ nghĩ làm thế nào C và trình biên dịch "đẹp" và đơn giản, và Python sống trong " thế giới lộn xộn "," cấp cao "
Kỹ sư đảo ngược

14

Nuitka là trình biên dịch Python sang C ++ liên kết với libpython. Nó dường như là một dự án tương đối mới. Tác giả tuyên bố cải thiện tốc độ so với CPython trên điểm chuẩn pystone.


10

Điều này thoạt nhìn có vẻ hợp lý, tuy nhiên, có rất nhiều điều bình thường trong Python không thể ánh xạ trực tiếp đến biểu diễn C mà không mang theo nhiều hỗ trợ thời gian chạy Python. Ví dụ, gõ vịt đến với tâm trí. Nhiều hàm trong Python đọc đầu vào có thể lấy một tệp hoặc đối tượng giống như tệp , miễn là nó hỗ trợ các hoạt động nhất định, ví dụ: đọc () hoặc readline (). Nếu bạn nghĩ về những gì sẽ cần để ánh xạ loại hỗ trợ này đến C, bạn bắt đầu tưởng tượng chính xác các loại mà hệ thống thời gian chạy Python đã làm.

Có các tiện ích như py2exe sẽ gói một chương trình Python và thời gian chạy thành một tệp thực thi duy nhất (càng xa càng tốt).


1
Điều gì sẽ xảy ra nếu mục tiêu của tôi là đảm bảo rằng mã biên dịch, bởi vì các ngôn ngữ được biên dịch tĩnh (ít nhất là theo ý kiến ​​của tôi) sẽ ít bị nổ tung hơn trong thời gian chạy? Có thể xác định rằng một số foo.xbiểu thức sẽ không hoạt động vì foosẽ không có xtại thời điểm nó được gọi. Có bất kỳ trình kiểm tra mã tĩnh nào cho Python không? Python có thể được biên dịch thành tập hợp .Net ...
Hamish Grubijan

10

Pyrex là một tập hợp con của ngôn ngữ Python biên dịch thành C, được thực hiện bởi người đầu tiên xây dựng danh sách hiểu cho Python. Nó chủ yếu được phát triển để xây dựng các hàm bao nhưng có thể được sử dụng trong bối cảnh tổng quát hơn. Cython là một ngã ba pyrex được duy trì tích cực hơn.


2
Cython là một ngã ba thân thiện được sử dụng rộng rãi hơn, được phát triển tích cực hơn của Pyrex.
Mike Graham


3

Jython có một trình biên dịch nhắm mục tiêu mã byte JVM. Mã byte hoàn toàn động, giống như ngôn ngữ Python! Rất tuyệt. (Có, như câu trả lời của Greg Hewgill, mã byte sử dụng thời gian chạy Jython và do đó, tệp jar Jython phải được phân phối cùng với ứng dụng của bạn.)


2

Psyco là một loại trình biên dịch (JIT) vừa đúng lúc: trình biên dịch động cho Python, chạy mã nhanh hơn 2 - 100 lần, nhưng nó cần nhiều bộ nhớ.

Nói tóm lại: nó chạy phần mềm Python hiện tại của bạn nhanh hơn nhiều, không có thay đổi trong nguồn của bạn nhưng nó không biên dịch thành mã đối tượng giống như trình biên dịch C.


2

Câu trả lời là "Có, nó có thể". Bạn có thể lấy mã Python và cố gắng biên dịch nó thành mã C tương đương bằng API CPython. Trên thực tế, đã từng có một dự án Python2C đã làm điều đó, nhưng tôi đã không nghe về nó trong nhiều năm (trở lại Python 1,5 ngày là lần cuối cùng tôi nhìn thấy nó.)

Bạn có thể cố gắng dịch mã Python sang C gốc càng nhiều càng tốt và quay lại API CPython khi bạn cần các tính năng Python thực tế. Tôi đã tự đùa giỡn với ý tưởng đó vào tháng một hoặc hai tháng trước. Tuy nhiên, rất nhiều công việc khủng khiếp và một lượng lớn các tính năng Python rất khó dịch sang các hàm C: lồng nhau, trình tạo, bất cứ thứ gì ngoại trừ các lớp đơn giản với các phương thức đơn giản, bất cứ thứ gì liên quan đến sửa đổi mô-đun toàn cầu từ bên ngoài mô-đun, v.v. , Vân vân.


2

Điều này không biên dịch Python thành mã máy. Nhưng cho phép tạo một thư viện chia sẻ để gọi mã Python.

Nếu những gì bạn đang tìm kiếm là một cách dễ dàng để chạy mã Python từ C mà không cần dựa vào công cụ thực thi. Bạn có thể tạo một thư viện chia sẻ từ mã python được gói bằng một vài lệnh gọi tới API nhúng Python . Ứng dụng này là một thư viện dùng chung, một .so mà bạn có thể sử dụng trong nhiều thư viện / ứng dụng khác.

Dưới đây là một ví dụ đơn giản tạo thư viện dùng chung, bạn có thể liên kết với chương trình C. Thư viện chia sẻ thực thi mã Python.

Tệp python sẽ được thực thi là 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

Bạn có thể thử nó với python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). Nó sẽ xuất ra:

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

Thư viện dùng chung sẽ được xác định bởi các mục sau callpython.h:

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

Liên kết callpython.clà:

// 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();
}

Bạn có thể biên dịch nó bằng lệnh sau:

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

Tạo một tệp có tên callpythonfromc.cnhư sau:

#include "callpython.h"

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

Biên dịch nó và chạy:

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

Đây là một ví dụ rất cơ bản. Nó có thể hoạt động, nhưng tùy thuộc vào thư viện, có thể vẫn khó sắp xếp các cấu trúc dữ liệu C thành Python và từ Python sang C. Mọi thứ có thể được tự động hóa phần nào ...

Nuitka có thể hữu ích.

Ngoài ra còn có numba nhưng cả hai đều không nhằm mục đích làm chính xác những gì bạn muốn. Có thể tạo tiêu đề C từ mã Python, nhưng chỉ khi bạn chỉ định cách chuyển đổi loại Python thành loại C hoặc có thể suy ra thông tin đó. Xem python astroid cho một phân tích ast ast Python.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.