在本教程中,我们将了解如何使用C编程语言创建一个非常简单的 Python 模块。我觉得这是一个很好的话题,因为我个人很难找到有效的简洁文档并向我展示了基础知识。
为什么需要 C 扩展?
C在 Python 语言成为瓶颈的情况下,能够编写扩展程序会派上用场。有时您需要低级语言的原始性能,例如C为了减少响应时间和处理时间等。
基本要求
在本教程中,我们将构建一个非常简单的C基于 Python 的模块,该模块将具有许多不同的功能,希望这些功能足以让您入门。
我们将创建 2 个不同的函数:
- 一个Hello World简单地执行打印的函数。
- 一个接收值的简单斐波那契函数n。
入门
让我们深入研究C代码。打开.c将包含新模块的文件并添加#include <Python.h>到顶部。这将引入必要的CPython 对象,使我们能够构建我们的模块。
#include <Python.h>
// Function 1: A simple 'hello world' function
static PyObject* helloworld(PyObject* self, PyObject* args)
{
printf("Hello World\n");
return Py_None;
}
// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
{ "helloworld", helloworld, METH_NOARGS, "Prints Hello World" },
{ NULL, NULL, 0, NULL }
};
// Our Module Definition struct
static struct PyModuleDef myModule = {
PyModuleDef_HEAD_INIT,
"myModule",
"Test Module",
-1,
myMethods
};
// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_myModule(void)
{
return PyModule_Create(&myModule);
}
我们的 setup.py 文件
值得庆幸的是,Python 包含一些使语言扩展更容易的模块。在这里,我们可以指定我们模块的名称并传入.c组成我们模块的必要文件。
from distutils.core import setup, Extension
setup(name = 'myModule', version = '1.0', \
ext_modules = [Extension('myModule', ['test.c'])])
构建和安装我们的模块
为了build和install我们新创建的C模块,我们必须执行以下操作:
python setup.py build
python setup.py install
连续运行时,您应该看到以下输出。然后我们可以启动我们的 Python 解释器并调用我们新创建的模块:
$ python3.6 setup.py build
running build
running build_ext
building 'myModule' extension
/usr/bin/clang -fno-strict-aliasing -Wsign-compare -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g -I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -c test.c -o build/temp.macosx-10.6-intel-3.6/test.o
/usr/bin/clang -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g build/temp.macosx-10.6-intel-3.6/test.o -o build/lib.macosx-10.6-intel-3.6/myModule.cpython-36m-darwin.so
$ python3.6 setup.py install
running install
running build
running build_ext
running install_lib
copying build/lib.macosx-10.6-intel-3.6/myModule.cpython-36m-darwin.so -> /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages
running install_egg_info
Removing /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/myModule-1.0-py3.6.egg-info
Writing /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/myModule-1.0-py3.6.egg-info
$ python3.6
Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import myModule
>>> myModule.helloworld()
Hello World
>>>
我们的斐波那契函数
现在让我们看一个更复杂的函数,它接收一个值n ,然后返回适当的斐波那契数。我们不会在memoization这里做任何花哨的事情,它将是一个普通的旧递归函数,具有糟糕的性能。然而,它将向我们展示如何在我们的C模块中接收一个值并返回一个值。
// Function 2: A C fibonacci implementation
// this is nothing special and looks exactly
// like a normal C version of fibonacci would look
int Cfib(int n)
{
if (n < 2)
return n;
else
return Cfib(n-1)+Cfib(n-2);
}
// Our Python binding to our C function
// This will take one and only one non-keyword argument
static PyObject* fib(PyObject* self, PyObject* args)
{
// instantiate our `n` value
int n;
// if our `n` value
if(!PyArg_ParseTuple(args, "i", &n))
return NULL;
// return our computed fib number
return Py_BuildValue("i", Cfib(n));
}
同样,我们应该像以前一样构建和安装它。然后我们可以像这样测试它:
>>> import myModule
>>> myModule.fib(2)
1
结论
希望您发现本教程很有用,它阐明了创建您自己的C基于模块的过程。如果您想留下一些反馈或提出其他问题,请随时在下面的评论部分中。