Section 190.1: 使用 C 扩展的 Hello World

以下 C 源文件(我们将其命名为 hello.c 用于演示)生成一个名为 hello 的扩展模块,其中包含一个函数 greet():

#include <Python.h>
#include <stdio.h>

#if PY_MAJOR_VERSION >= 3
#define IS_PY3K
#endif
static PyObject *hello_greet(PyObject *self, PyObject *args)
{
  const char *input;
  if (!PyArg_ParseTuple(args, "s", &input)) {
    return NULL;
  }
  printf("%s", input);
  Py_RETURN_NONE;
}

static PyMethodDef HelloMethods[] = {
  { "greet", hello_greet, METH_VARARGS, "Greet the user" },
  { NULL, NULL, 0, NULL }
};

#ifdef IS_PY3K
static struct PyModuleDef hellomodule = {
  PyModuleDef_HEAD_INIT, "hello", NULL, -1, HelloMethods
};

PyMODINIT_FUNC PyInit_hello(void)
{
  return PyModule_Create(&hellomodule);
}
#else
PyMODINIT_FUNC inithello(void)
{
  (void) Py_InitModule("hello", HelloMethods);
}
#endif

要使用 gcc 编译器编译该文件,请在您喜欢的终端中运行以下命令:

gcc /path/to/your/file/hello.c -o /path/to/your/file/hello

要执行我们之前编写的 greet() 函数,请在相同目录下创建一个文件,并将其命名为 hello.py:

import hello  # 导入编译后的库
hello.greet("Hello!")  # 使用 "Hello!" 作为参数运行 greet() 函数

Section 190.2: C 使用 C++ 和 Boost 的 C 扩展

这是一个使用 C++ 和 Boost 的 C 扩展的基本示例。

C++ 代码

将以下 C++ 代码保存为 hello.cpp:

#include <boost/python/module.hpp>
#include <boost/python/list.hpp>
#include <boost/python/class.hpp>
#include <boost/python/def.hpp>

// 返回一个 Hello World 字符串
std::string get_hello_function()
{
    return "Hello world!";
}

// hello 类,可以返回一个包含 count 个 Hello World 字符串的列表
class hello_class
{
public:
    // 在构造函数中接收问候消息
    hello_class(std::string message) : _message(message) {}
    // 在 Python 列表中返回消息 count 次
    boost::python::list as_list(int count)
    {
        boost::python::list res;
        for (int i = 0; i < count; ++i) {
            res.append(_message);
        }
        return res;
    }

private:
    std::string _message;
};

// 定义一个名为 "hello" 的 Python 模块
BOOST_PYTHON_MODULE(hello)
{
    // 在这里声明模块中应该暴露的函数和类

    // 将 get_hello_function 暴露为 Python 函数
    boost::python::def("get_hello", get_hello_function);

    // 将 hello_class 暴露为 Python 类
    boost::python::class_<hello_class>("Hello", boost::python::init<std::string>())
        .def("as_list", &hello_class::as_list);
}

编译

要将此代码编译为 Python 模块,您需要 Python 头文件和 Boost 库。此示例在 Ubuntu 12.04 上使用 Python 3.4 和 gcc 编写。Boost 支持许多平台。在 Ubuntu 上,需要的包通过以下命令安装:

sudo apt-get install gcc libboost-dev libpython3.4-dev

将源文件编译为 .so 文件,以便在 Python 路径上将其作为模块导入:

gcc -shared -o hello.so -fPIC -I/usr/include/python3.4 hello.cpp -lboost_python-py34 -lboost_system-l:libpython3.4m.so

Python 代码

在文件 example.py 中的 Python 代码如下:

import hello

print(hello.get_hello())

h = hello.Hello("World hello!")
print(h.as_list(3))

运行 python3 example.py 将输出以下内容:

Hello world!
['World hello!', 'World hello!', 'World hello!']

Section 190.3: 将打开的文件传递给 C 扩展

从 Python 将打开的文件对象传递给 C 扩展代码。

您可以使用 PyObject_AsFileDescriptor 函数将文件转换为整数文件描述符:

PyObject *fobj;
int fd = PyObject_AsFileDescriptor(fobj);
if (fd < 0){
  return NULL;
}

要将整数文件描述符转换回 Python 对象,请使用 PyFile_FromFd。

int fd; /* Existing file descriptor */
PyObject *fobj = PyFile_FromFd(fd, "filename","r",-1,NULL,NULL,NULL,1);