将Python(可能通过中间C表示形式)编译为机器代码的可行性如何?
大概需要链接到Python运行时库,并且Python标准库中Python本身的任何部分也需要进行编译(并链接)。
另外,如果您想对表达式进行动态求值,则需要捆绑Python解释器,但是也许不允许这样做的Python子集仍然有用。
它会提供任何速度和/或内存使用优势吗?大概可以省去Python解释器的启动时间(尽管共享库在启动时仍需要加载)。
将Python(可能通过中间C表示形式)编译为机器代码的可行性如何?
大概需要链接到Python运行时库,并且Python标准库中Python本身的任何部分也需要进行编译(并链接)。
另外,如果您想对表达式进行动态求值,则需要捆绑Python解释器,但是也许不允许这样做的Python子集仍然有用。
它会提供任何速度和/或内存使用优势吗?大概可以省去Python解释器的启动时间(尽管共享库在启动时仍需要加载)。
Answers:
尝试使用ShedSkin从 Python到C ++的编译器,但这远非完美。如果仅需要加速,则还有Psyco-Python JIT。但是恕我直言,这不值得付出努力。对于速度至关重要的代码部分,最好的解决方案是将它们编写为C / C ++扩展。
就像@Greg Hewgill所说的那样,有很多理由说明为什么这并不总是可能的。但是,某些类型的代码(例如非常算法的代码)可以变成“真实的”机器代码。
有几种选择:
之后,您可以使用现有的软件包之一(freeze,Py2exe,PyInstaller)将所有内容放入一个二进制文件中。
总而言之:您的问题没有一般性的答案。如果您具有对性能至关重要的Python代码,请尝试使用尽可能多的内置功能(或询问“如何使我的Python代码更快”问题)。如果那没有帮助,请尝试识别代码并将其移植到C(或Cython)并使用扩展名。
py2c(https://github.com/pradyun/Py2C)可以将python代码转换为c / c ++我是py2c的开发人员。
PyPy是一个在Python中重新实现Python的项目,使用对本机代码的编译作为实现策略之一(其他方法是具有JIT的VM,使用JVM等)。他们的编译C版本平均运行速度比CPython慢,但对于某些程序,运行速度要快得多。
Shedskin是一个实验性的Python到C ++编译器。
Pyrex是专门用于编写Python扩展模块的语言。它旨在弥合Python的精美,高级,易于使用的世界与C的混乱,低级的世界之间的鸿沟。
乍看起来,这似乎是合理的,但是在Python中,有很多普通的东西不能直接映射到C表示形式,而又不会继承很多Python运行时支持。例如,想到鸭式打字。Python中的许多读取输入的函数可以获取一个文件或类似文件的文件对象,只要它支持某些操作即可。read()或readline()。如果您考虑将这种类型的支持映射到C会花费什么,那么您将开始完全想象Python运行时系统已经完成的各种工作。
有诸如py2exe之类的实用程序,它将Python程序和运行时捆绑到一个可执行文件中(尽可能)。
foo.x
表达不会起作用,因为foo
不会有x
在它被调用的时候。Python是否有任何静态代码检查器?可以将Python编译为.Net程序集……
Pyrex是可编译为C的Python语言的子集,由最初为Python 建立列表理解的人完成。它主要是为建筑包装纸开发的,但可以在更广泛的范围内使用。 Cython是派热克斯(pyrex)维护得更积极的分支。
一些额外的参考:
https://github.com/dropbox/pyston是Dropbox开发的Python JIT编译器
http://pythran.readthedocs.io/是用于C ++编译器的编译时python,用于科学计算
https://github.com/cosmo-ethz/hope是一个JIT python到C ++的转换器,用于科学计算
这不会将Python编译为机器代码。但是允许创建一个共享库来调用Python代码。
如果您正在寻找的是一种不依赖execp的方式从C运行Python代码的简便方法。您可以从包装有几次对Python嵌入API的调用的python代码生成共享库。好了,该应用程序是一个共享库,一个.so,因此您可以在许多其他库/应用程序中使用。
这是一个创建共享库的简单示例,您可以将其与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,但是它们都不打算完全按照自己的意愿去做。可以从Python代码生成C标头,但前提是您指定如何将Python类型转换为C类型或可以推断出该信息。有关Python ast分析器,请参见python astroid。