Чи можливо компілювати Python для машинного коду?


128

Наскільки можливим буде компілювати Python (можливо, через проміжне представлення C) у машинний код?

Імовірно, знадобиться посилання на бібліотеку виконання Python, і будь-які частини стандартної бібліотеки Python, які були самі Python, також повинні бути складені (і пов'язані з ними).

Крім того, вам потрібно було б поєднати інтерпретатор Python, якщо ви хочете зробити динамічну оцінку виразів, але, можливо, підмножина Python, що цього не дозволяє, все-таки буде корисною.

Чи забезпечив би це якісь переваги швидкості та / або використання пам'яті? Імовірно, час запуску інтерпретатора Python буде усунутий (хоча спільні бібліотеки все ще потребують завантаження при запуску).


2
До речі, ваше питання було б зрозумілішим, якщо ви запитаєте "машинний код", а не об'єктний код.
Торстен Марек

Відповіді:


31

Спробуйте компілятор ShedSkin Python-to-C ++, але він далеко не ідеальний. Також є Psyco - Python JIT, якщо потрібне лише прискорення. Але ІМХО на це не варто докладати зусиль. Для критично важливих для швидкості частин коду найкращим рішенням буде записувати їх як розширення C / C ++.


5
FYI, ShedSkin відмовився від підтримки Windows.
sorin

2
@sorin: ну сьогодні він підтримує windows ... code.google.com/p/shedskin/downloads/…

2
Найкращим рішенням, як швидко, все-таки може стати PyPy .
Cees Timmerman

Шедкін не працював над цим вже майже два роки. :(
Перкінс

53

Як говорить @Greg Hewgill, є вагомі причини, чому це не завжди можливо. Однак певні види коду (наприклад, дуже алгоритмічний код) можна перетворити на "справжній" машинний код.

Є кілька варіантів:

  • Використовуйте Psyco , який динамічно випромінює машинний код. Слід ретельно вибирати, які методи / функції конвертувати.
  • Використовуйте Cython - мову, схожу на Python, яка компілюється в розширення Python C
  • Використовуйте PyPy , у якого є перекладач з RPython ( обмежений підмножина Python, який не підтримує деякі найбільш "динамічні" функції Python) на C або LLVM.
    • PyPy все ще дуже експериментальний
    • не всі розширення будуть присутні

Після цього ви можете використовувати один із існуючих пакетів (заморозити, Py2exe, PyInstaller), щоб розмістити все в один бінарний файл.

Загалом: на ваше запитання немає загальної відповіді. Якщо у вас є Python-код, який є критичним для продуктивності, спробуйте використовувати якомога більше вбудованих функціональних можливостей (або задайте питання "Як зробити мій код Python швидше"). Якщо це не допомагає, спробуйте визначити код та перенести його на C (або Cython) та скористайтеся розширенням.


3
Pypy є спадкоємцем Psyco
bcattle

19

py2c ( https://github.com/pradyun/Py2C ) може перетворити код python в c / c ++ Я є сольним розробником py2c.


Це виглядає як корисний інструмент. Чи все ще зберігається?
Андерсон Грін

@AndersonGreen Це було на ранній стадії розвитку, коли я працював над ним (напевно, схоже зараз). Я покинув проект, тому що I̶'̶m̶ ̶b̶u̶s̶y̶ я лінивий. Якщо ви ще не помітили "Важливого" тексту, він перейшов до GitHub зараз.
Рамчандра Апте

Посилання вказує на unvanquished-installer , який, схоже, є іншим проектом. Чи все ще py2c доступний на GitHub?
Андерсон Грін

@AndersonGreen Ого, що так довго було непоміченим! Ось ви йдете.
Рамчандра Апте

Посилання на code.google.com/p/py2c як і раніше вказує на незапрошений інсталятор, тому його потрібно оновити зараз.
Андерсон Грін

15

PyPy - це проект по повторному впровадженню Python в Python, використовуючи компіляцію до нативного коду як одну із стратегій реалізації (інші - це VM з JIT, використовуючи JVM тощо). Їх складені версії C працюють в середньому повільніше, ніж CPython, але для деяких програм набагато швидше.

Shedskin - експериментальний компілятор Python-to-C ++.

Pyrex - мова, спеціально розроблена для написання модулів розширення Python. Він призначений для усунення розриву між приємним, високим рівнем, легким у користуванні світом Python та безладним світом низького рівня C.


3
Cython - це більш широко використовуваний, більш активно розвинений дружній вилок Pyrex.
Майк Грехем

"приємний, високий рівень, простий у користуванні світ Python та безладний світ низького рівня C" - смішно, я просто думав, як C і асемблер "приємні" і прості, а Python живе в " безладний "," світ високого рівня "
інженер, що перевернувся,


10

На перший погляд це може здатися розумним, однак у Python є багато звичайних речей, які не підлягають прямому відображенню до представлення C, не переносячи велику підтримку виконання Python. Наприклад, на думку приходить введення качки. Багато функцій в Python, які читають вхід, можуть приймати файл або подібний до файлу об'єкт, якщо він підтримує певні операції, наприклад. read () або readline (). Якщо ви подумаєте, що знадобиться для відображення цього типу підтримки на C, ви починаєте уявляти саме ті речі, які вже виконує система виконання Python.

Є утиліти, такі як py2exe, які поєднають програму Python та час виконання в єдиний виконуваний файл (наскільки це можливо).


1
Що робити, якщо моєю метою було переконатися, що код збирається, оскільки статично складені мови (принаймні, на мою думку) мають меншу ймовірність підірватись під час виконання? Чи можна визначити, що якийсь foo.xвираз не буде працювати, тому що fooне матиме xтого часу, коли він буде викликаний. Чи є статичні перевірки коду для Python? Python можна скласти до .Net Assembly ...
Гаміш Грубіян

10

Pyrex - це підмножина мови Python, яка компілюється на C, зроблена хлопцем, який першим побудував розуміння списку для Python. Він був в основному розроблений для побудови обгортки, але може використовуватися в більш загальному контексті. Cython - це більш активно підтримувана вилка pyrex.


2
Cython - це більш широко використовуваний, більш активно розвинений дружній вилок Pyrex.
Майк Грехем


3

У Jython є компілятор, орієнтований на байт-код JVM. Байт-код є повністю динамічним, як і сама мова Python! Дуже круто. (Так, як натякає на відповідь Грега Х'югілла, байт-код використовує час виконання Jython, і тому файл Jython jar повинен поширюватися разом із вашим додатком.)


2

Psyco - це своєрідний компілятор (JIT): динамічний компілятор для Python, працює в 2-100 разів швидше, але йому потрібно багато пам'яті.

Коротше кажучи: він запускає ваше існуюче програмне забезпечення Python набагато швидше, не змінюючи джерела, але він не компілює об'єктний код так, як і компілятор C.


2

Відповідь «Так, це можливо». Ви можете взяти код Python і спробувати скомпілювати його в еквівалентний код C за допомогою API CPython. Насправді раніше існував проект Python2C, який робив саме це, але я про це не чув уже багато років (ще в Python 1,5 дня - це коли я востаннє бачив його.)

Ви можете максимально спробувати перекласти код Python в рідний C і повернутися до API CPython, коли вам потрібні фактичні функції Python. Я грав із цією ідеєю сам останній місяць-два. Однак, це дуже багато роботи, і величезну кількість функцій Python дуже важко перевести на C: вкладені функції, генератори, все, крім простих класів простими методами, будь-що, що стосується зміни глобальних модулів поза модулем тощо. тощо.


2

Це не компілює Python в машинний код. Але дозволяє створити спільну бібліотеку для виклику коду Python.

Якщо ви шукаєте, це простий спосіб запустити Python-код з C, не покладаючись на речі execp. Ви можете створити спільну бібліотеку з коду python, обгорнутого кількома дзвінками до API вбудовування Python . Додаток - це спільна бібліотека, тому що ви можете використовувати в багатьох інших бібліотеках / програмах.

Ось простий приклад, який створює спільну бібліотеку, яку ви можете зв’язати з програмою C. Спільна бібліотека виконує код Python.

Файл python, який буде виконуватися 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

Ви можете спробувати python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). Він виведе:

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

Спільна бібліотека буде визначена наступним чином callpython.h:

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

Пов’язане callpython.c:

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

Ви можете скласти його за допомогою наступної команди:

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

Створіть файл з назвою, callpythonfromc.cякий містить наступне:

#include "callpython.h"

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

Складіть його та запустіть:

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

Це дуже базовий приклад. Це може працювати, але залежно від бібліотеки може бути важко серіалізувати структури даних C на Python та з Python на C. Речі можуть бути дещо автоматизовані ...

Нуїтка може бути корисною.

Також є numba, але вони обоє не прагнуть робити те, що саме ви хочете. Генерування заголовка C з коду Python можливо, але лише якщо ви вкажете, як перетворити типи Python у типи C або ви зможете зробити цю інформацію. Дивіться астроїд пітона для аналізу аналізатора Python ast.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.