这是可行的编纂Python机代码吗?
-
02-07-2019 - |
题
如何可行的,它将编制Python(可能通过一个中间C表示)成机器码?
据推测这将需要链接到一条巨蟒runtime library,以及任何部分的蟒蛇的标准图书馆,这是蟒蛇自己也会需要编制(和链接)。
还有,你会需要捆绑Python解释,如果你想要做的动态评估的表达形式,但也许是一个子集,蟒蛇不能让这将仍然是有用的。
将它提供的任何速度和/或存储器使用的优势?据推测的启动时间蟒蛇的口译将被消除的(虽然公共图书馆仍将需要的装载在启动时)。
解决方案
尝试 ShedSkin Python-to-C ++编译器,但它远非完美。还有Psyco - Python JIT,如果只需要加速。但恕我直言,这不值得努力。对于速度至关重要的代码部分,最佳解决方案是将它们编写为C / C ++扩展。
其他提示
作为@格雷格Hewgill说它有很好的理由为什么这不是总是可能的。然而,某些类型的代码(如非常码算法)可以变成"真正的"机器码。
有几种选择:
- 使用 Psyco, ,其发射机代码的动态。你应该谨慎选择哪些方法/功能转换,虽然。
- 使用 Cython, ,这是一个巨蟒喜欢 语言汇编成一Python C扩展
- 使用 PyPy, ,其中有一个翻译从RPython(a 受限制的子集 Python不支持某些最"动态"的特点Python)至C或编程.
- PyPy仍然是高度实验性
- 不是所有的扩展将本
在那之后,你可以使用一个现有的软件包(冻结,Py2exe,PyInstaller)把一切都进入一个二进制的。
所有在所有:没有任何一般性的回答你的问题。如果你有Python代码性能至关重要的,尝试使用尽可能多的系统功能的可能(或者问一个"我怎么做我的代码的更快"问题)。如果没有帮助,试图识别码和口它C(或Cython)和使用的扩展。
py2c( http://code.google.com/p/py2c )可以将python代码转换为c / C ++ 我是py2c的独立开发者。
乍一看这似乎是合理的,但是Python中有很多普通的东西不能直接映射到C表示而不需要承载很多Python运行时支持。例如,想到鸭子打字。 Python中用于读取输入的许多函数可以采用文件或类似文件的对象,只要它支持某些操作,例如。 read()或readline()。如果您考虑将此类支持映射到C所需的内容,您就会开始想象Python运行时系统已经完成的各种事情。
py2exe 等实用程序将Python程序和运行时捆绑到一个可执行文件中(目前为止)尽可能)。
一些额外参考文献:
https://github.com/dropbox/pyston 是JIT编译器Python开发自然
http://pythran.readthedocs.io/ 是的编写时python C++翻译用于科学计算
https://github.com/cosmo-ethz/hope 是JIT python C++翻译用于科学计算
Jython有一个针对JVM字节码的编译器。字节码是完全动态的,就像Python语言本身一样!很酷。 (是的,正如Greg Hewgill的回答所说,字节码确实使用了Jython运行时,因此Jython jar文件必须随应用程序一起分发。)
Psyco 是一种即时(JIT)编译器:Python的动态编译器,运行代码的速度提高了2-100倍,但它需要很多内存。
简而言之:它可以更快地运行您现有的Python软件,但源代码没有变化,但它不像C编译器那样编译成目标代码。
答案是“是的,有可能”。您可以使用Python代码并尝试使用CPython API将其编译为等效的C代码。事实上,曾经有一个Python2C项目就是这样,但我多年没有听说过它(回到Python 1.5天就是我上次看到它的时候。)
您可以尝试尽可能地将Python代码转换为本机C,并在需要实际Python功能时回退到CPython API。在过去的一两个月里,我一直在玩弄这个想法。然而,这是一项非常多的工作,并且大量的Python特性很难转换为C:嵌套函数,生成器,除了简单类的简单类,任何涉及从模块外部修改模块全局变量的东西,等等等等。
这不会将Python编译为机器代码。但允许创建一个共享库来调用Python代码。
如果您正在寻找的是从C运行Python代码而不依赖于execp的简单方法。您可以从python代码生成一个共享库,其中包含对 Python嵌入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( '你好')代码>。它将输出:
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 。