Возможно ли скомпилировать Python в машинный код?


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

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

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

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

12 113

12 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Psyco это своего рода JIT-компилятор: динамический компилятор для Python, запускает код в 2-100 раз быстрее, но ему требуется много памяти.

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

ответ "Да, возможно". Вы можете взять код Python и попытаться скомпилировать его в эквивалентный код C с помощью CPython API. На самом деле, раньше был проект Python2C, который сделал именно это, но я не слышал об этом много лет (назад в Python 1.5 days, когда я в последний раз видел его.)

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

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

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

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

Nuitka может быть полезным.

есть numba но они оба не стремятся делать то, что вы хотите точно. Создание заголовка C из кода Python возможно, но только если вы укажете, как преобразовать типы Python в типы C или можете вывести эту информацию. Смотрите python astroid для анализатора Python ast.