在做毕业设计的时候,我用Python来实现项目的应用层,底层的驱动由于对时间要求比较严格(微秒级),用Python会出问题,毕竟Python就不是用来做底层开发的。这就涉及到在Python中使用C程序的问题,下面给出几种解决方案。
使用这个模块,我们可以执行一些外部程序,并且获取其返回值以及执行状态,如
status, output = commands.getstatusoutput("sudo ./main")
但是这种方式的局限性比较大,必须等待外部程序执行完毕才能继续执行,外部模块之间难以完成通信。优点是几乎可以融合任何语言编写的可执行程序。
这个模块可以加载dll(Windows)或者so(Linux),并且执行其中的函数,另外,它也提供了一些数据类型,这些类型与C语言中的基本数据类型一一对应,甚至提供了指针的使用,缺点是如果你的动态链接库依赖与第三方的库,那么将没有办法使用。详情参见ctypes — A foreign function library for Python
要编写Python的模块,需要对我们编写的C程序做一层封装,从而让Python可以顺利与C模块通信。虽然说起来很高大上,但是做起来并不困难,由于我也不太熟悉一些专业术语,直接上模板了。详细的文档参见Extending Python with C or C++以及Building C and C++ Extensions with distutils
/* Example of embedding Python in another program */
#include "Python.h"
void initxyzzy(void); /* Forward */
main(int argc, char **argv)
{
/* Pass argv[0] to the Python interpreter */
Py_SetProgramName(argv[0]);
/* Initialize the Python interpreter. Required. */
Py_Initialize();
/* Add a static module */
initxyzzy();
/* Define sys.argv. It is up to the application if you
want this; you can also leave it undefined (since the Python
code is generally not a main program it has no business
touching sys.argv...)
If the third argument is true, sys.path is modified to include
either the directory containing the script named by argv[0], or
the current working directory. This can be risky; if you run
an application embedding Python in a directory controlled by
someone else, attackers could put a Trojan-horse module in the
directory (say, a file named os.py) that your application would
then import and run.
*/
PySys_SetArgvEx(argc, argv, 0);
/* Do some application specific code */
printf("Hello, brave new world\n\n");
/* Execute some Python statements (in module __main__) */
PyRun_SimpleString("import sys\n");
PyRun_SimpleString("print sys.builtin_module_names\n");
PyRun_SimpleString("print sys.modules.keys()\n");
PyRun_SimpleString("print sys.executable\n");
PyRun_SimpleString("print sys.argv\n");
/* Note that you can call any public function of the Python
interpreter here, e.g. call_object(). */
/* Some more application specific code */
printf("\nGoodbye, cruel world\n");
/* Exit, cleaning up the interpreter */
Py_Exit(0);
/*NOTREACHED*/
}
/* A static module */
/* 'self' is not used */
static PyObject *
xyzzy_foo(PyObject *self, PyObject* args)
{
return PyInt_FromLong(42L);
}
static PyMethodDef xyzzy_methods[] = {
{"foo", xyzzy_foo, METH_NOARGS,
"Return the meaning of everything."},
{NULL, NULL} /* sentinel */
};
void
initxyzzy(void)
{
PyImport_AddModule("xyzzy");
Py_InitModule("xyzzy", xyzzy_methods);
}
你的C代码需要以这个模板为框架,注意以下几点
1. xyzzy
是你的模块的名称,其它地方不要修改,因为Python对于模块的命名有比较严格的规范,随意命名可能会出现问题。
2. 你的主体程序需要在xyzzy_foo
这个函数中执行,当然也可以在这个函数中调用,这个函数将来会与模块的接口绑定,从而实现在Python中调用执行。
3. xyzzy_methods
这个数组将你的模块的接口与内部函数对应起来,其中foo
就是将来你在Python中调用的方法名。
4. initxyzzy
用于初始化你的模块,基本主需要修改以下模块的名称即可
5. 主函数中有一些附加代码,比如获取命令行参数,如果不需要可以去除。
from distutils.core import setup, Extension
module1 = Extension('demo',
define_macros = [('MAJOR_VERSION', '1'),
('MINOR_VERSION', '0')],
include_dirs = ['/usr/local/include'],
libraries = ['tcl83'],
library_dirs = ['/usr/local/lib'],
sources = ['demo.c'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a demo package',
author = 'Martin v. Loewis',
author_email = '[email protected]',
url = 'https://docs.python.org/extending/building',
long_description = '''
This is really just a demo package.
''',
ext_modules = [module1])
这个Python代码用于生成你的Python模块的动态链接库,它的作用实际上就是生成一条编译命令,理论上手动生成也是可以的,下面说几点注意事项:
最后,你只需要执行以下命令,即可生成库
python setup.py build
使用以下命令将安装库,从而可以在任意地方使用
python setup.py install