Возможно ли скомпилировать Python для машинного кода? - PullRequest
116 голосов
/ 26 сентября 2008

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

Предположительно, для этого потребуется ссылка на библиотеку времени выполнения Python, и любые части стандартной библиотеки Python, которые сами были Python, также должны были бы быть скомпилированы (и связаны).

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

Обеспечит ли это какие-либо преимущества в скорости и / или использовании памяти? Предположительно время запуска интерпретатора Python будет устранено (хотя разделяемые библиотеки все равно будут загружаться при запуске).

Ответы [ 13 ]

49 голосов
/ 26 сентября 2008

Как говорит @Greg Hewgill, есть веские причины, по которым это не всегда возможно. Однако некоторые виды кода (например, очень алгоритмический код) можно превратить в «настоящий» машинный код.

Есть несколько вариантов:

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

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

В целом: нет общего ответа на ваш вопрос. Если у вас есть код Python, который критичен к производительности, постарайтесь использовать как можно больше встроенных функций (или задайте вопрос «Как сделать мой код Python быстрее»). Если это не помогает, попробуйте определить код и перенести его на C (или Cython) и использовать расширение.

24 голосов
/ 26 сентября 2008

Попробуйте ShedSkin Компилятор Python-to-C ++, но он далек от совершенства. Также есть Psyco - Python JIT, если требуется только ускорение. Но ИМХО это не стоит усилий. Для критичных по скорости частей кода лучшим решением было бы написать их как расширения C / C ++.

17 голосов
/ 10 июля 2012

py2c (http://code.google.com/p/py2c) может конвертировать код Python в c / c ++ Я сольный разработчик py2c.

14 голосов
/ 09 апреля 2014

Nuitka - это компилятор Python to C ++, который ссылается на libpython. Похоже, это относительно новый проект. Автор утверждает, что улучшение скорости по сравнению с CPython в тесте Pystone.

14 голосов
/ 26 сентября 2008

PyPy - это проект по переопределению Python в Python, использующий компиляцию в нативный код в качестве одной из стратегий реализации (другими являются ВМ с JIT, использование JVM и т. Д.). Их скомпилированные версии C работают в среднем медленнее, чем CPython, но гораздо быстрее для некоторых программ.

Шедскин - экспериментальный компилятор Python-to-C ++.

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

10 голосов
/ 26 сентября 2008

Pyrex - это подмножество языка Python, который компилируется в C, созданный парнем, который впервые создал список пониманий для Python. Он был в основном разработан для создания оболочек, но может использоваться в более общем контексте. Cython - более активно поддерживаемый форк пирекс.

9 голосов
/ 26 сентября 2008

На первый взгляд это может показаться разумным, однако в Python есть много простых вещей, которые нельзя напрямую сопоставить с представлением C, не перенося большую часть поддержки времени исполнения Python. Например, на ум приходит утка. Многие функции в Python, которые читают ввод, могут принимать файл или файлоподобный объект, если он поддерживает определенные операции, например. read () или readline (). Если вы подумаете о том, что потребуется, чтобы отобразить этот тип поддержки на C, вы начнете представлять себе именно то, что система Python уже выполняет.

Существуют такие утилиты, как py2exe , которые объединяют программу Python и среду выполнения в один исполняемый файл (насколько это возможно).

5 голосов
/ 30 августа 2015

Некоторые дополнительные ссылки:

3 голосов
/ 26 сентября 2008

Jython имеет компилятор, ориентированный на байт-код JVM. Байт-код полностью динамический, как и сам язык Python! Очень круто. (Да, как намекает на ответ Грег Хьюгилл, байт-код действительно использует среду выполнения Jython, и поэтому Jar-файл Jython должен распространяться вместе с приложением.)

2 голосов
/ 11 мая 2014

Это не компилирует Python в машинный код. Но позволяет создать разделяемую библиотеку для вызова кода Python.

Если то, что вы ищете, это простой способ запуска кода Python из C без использования execp. Вы можете сгенерировать разделяемую библиотеку из кода Python, заключенного в несколько вызовов API встраивания Python . Ну, приложение - это разделяемая библиотека, так что вы можете использовать ее во многих других библиотеках / приложениях.

Вот простой пример создания общей библиотеки, которую вы можете связать с программой на Си. Общая библиотека выполняет код 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 astroid для анализа Python ast.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...