Можно ли скомпилировать Python для машинного кода?

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

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

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

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

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

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

Ответ 11

Ответ: "Да, это возможно". Вы можете взять код Python и попытаться скомпилировать его в эквивалентный код C, используя API-интерфейс CPython. Фактически, раньше существовал проект Python2C, но я не слышал об этом за многие годы (еще в Python 1,5 дня, когда я в последний раз его видел).

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

Ответ 12

Это не скомпилирует 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. Вещи могут быть несколько автоматизированы...

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

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