编译Python到机器代码是否可行?

将Python(可能通过中间的C表示)编译成机器代码有多大的可行性?

据推测,它将需要链接到一个Python运行时库,Python标准库中的任何部分都是Python本身需要编译(并链接)。

另外,如果要对expression式进行dynamic评估,则需要捆绑Python解释器,但也许是不允许使用的Python子集仍然有用。

它会提供任何速度和/或内存使用优势? 据推测,Python解释器的启动时间将被消除(尽pipe共享库在启动时仍然需要加载)。

尝试ShedSkin的 Python到C ++编译器,但它远非完美。 如果只需要加速,还有Psyco – Python JIT。 但恕我直言,这是不值得的努力。 对于速度至关重要的代码部分,最好的解决办法是将它们写成C / C ++扩展。

正如@Greg Hewgill所说的那样,为什么这并不总是可能的。 但是,某些types的代码(如非常algorithm的代码)可以变成“真实的”机器代码。

有几个选项:

  • 使用Psyco ,dynamic地发出机器码。 但是,您应该仔细select要转换的方法/函数。
  • 使用Cython ,这是一种类似 Python的语言,编译成Python C扩展
  • 使用PyPy ,它有一个来自RPy​​thon(Python的一个受限制的子集 ,不支持Python的一些“dynamic”特性)的转换器到C或LLVM。
    • PyPy仍然是高度实验性的
    • 不是所有的扩展都会出现

之后,您可以使用其中一个现有软件包(freeze,Py2exe,PyInstaller)将所有内容放入一个二进制文件中。

总而言之:你的问题没有一般的答案。 如果您的Python代码对性能至关重要,请尝试使用尽可能多的内置function(或者询问“如何使我的Python代码更快”问题)。 如果这没有帮助,请尝试识别代码并将其移植到C(或Cython)并使用扩展名。

py2c( http://code.google.com/p/py2c )可以将python代码转换为c / c ++我是py2c的独立开发者。

PyPy是一个在Python中重新实现Python的项目,使用编译为本地代码作为实现策略之一(其他人是使用JIT的VM,使用JVM等)。 他们编译的C版本平均运行速度比CPython慢​​,但是对于某些程序来说要快得多。

Shedskin是一个实验性的Python-to-C ++编译器。

Pyrex是专门为编写Python扩展模块而devise的语言。 它旨在弥补Python的高级,易于使用的世界与凌乱的低级世界之间的鸿沟。

这看起来似乎是合理的,但是Python中有很多普通的东西,它们不能直接映射到C表示,而没有进行大量的Python运行时支持。 例如,鸭子打字想到。 Python中许多读取input的函数只要支持某些操作,就可以采用文件或文件类对象,例如。 read()或readline()。 如果考虑将这种types的支持映射到C需要花费多less时间,那么您就开始想象Python运行时系统已经完成的各种事情。

有一些实用程序,比如py2exe ,将Python程序和运行时绑定到一个可执行文件(尽可能)。

Pyrex是编译为C的Python语言的一个子集,由首先为Python构build列表parsing的人完成。 它主要是为了构build包装而开发的,但是可以在更一般的情况下使用。 Cython是pyrex的一个更积极维护的分支。

Nuitka是一个Python到C ++编译器,可以链接到libpython。 这似乎是一个相对较新的项目。 作者声称在pystone基准上比CPython 提高了速度 。

Psyco是一种即时(JIT)编译器:用于Python的dynamic编译器,运行速度快2-100倍,但需要大量内存。

简而言之:它可以更快地运行现有的Python软件,而不会改变源代码,但它不会像C编译器那样编译代码。

Jython有一个针对JVM字节码的编译器。 字节码是完全dynamic的,就像Python语言本身一样! 很酷。 (是的,正如Greg Hewgill的回答所暗示的,字节码确实使用了Jython运行时,所以Jython jar文件必须与您的应用程序一起分发。)

答案是“是的,这是可能的”。 您可以使用Python代码,并尝试使用CPython API将其编译为等效的C代码。 事实上,过去有一个Python2C项目就是这么做的,但是我多年以来都没有听说过这个(在1.5天的Python版本中是我上次看到它的时候)。

您可以尝试将Python代码尽可能地转换为本地C,并在您需要实际的Pythonfunction时回退到CPython API。 上个月我一直在玩这个想法。 然而,这是一个非常多的工作,并且大量的Python特性很难转换成C:嵌套函数,生成器,只有简单类的简单类,任何涉及从模块外部修改模块全局variables的东西等等等

这不会将Python编译成机器码。 但是允许创build一个共享库来调用Python代码。

如果你正在寻找的是一个简单的方法来从C运行Python代码,而不依赖于execp的东西。 你可以从python代码生成一个共享库,包含几个对PythonembeddedAPI的调用 。 那么这个应用程序是一个共享库,所以你可以在许多其他的库/应用程序中使用。

下面是一个简单的例子,它可以创build一个共享库,你可以链接到一个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 

创build一个名为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,但他们都没有瞄准做你想要的东西。 只有在指定如何将Pythontypes转换为Ctypes或可以推断出这些信息的情况下,才可以从Python代码生成C头文件。 请参阅python astroid for Python ast分析器。