title: Python-C扩展模块移植到3.0指南 source: Python官方文档 original_path: /田浩然上传的资料/电子书/Python/python-3.0.1-docs-pdf-a4/docs-pdf/howto-cporting.pdf author: Guido van Rossum, Fred L. Drake, Jr. size: 100KB pages: 5 date_processed: 2026-09-30 method: PDF文本提取 status: done

Python C扩展模块移植到3.0指南

概述

本文档说明Python 3.0中C-API的不兼容性及其迁移方法。虽然改变C-API不是Python 3.0的主要目标,但许多Python级别的变更使得保持2.x的API完整变得不可能。

1. 条件编译

最简单的跨版本兼容方法是检查PY_MAJOR_VERSION:

#if PY_MAJOR_VERSION >= 3
#define IS_PY3K
#endif

对于缺失的API函数,可在条件块内将其别名化为等效函数。

2. 对象API变更

2.1 str/unicode统一

Python 3.0的str()类型(C中为PyString_函数)等价于2.x的unicode()(PyUnicode_)。旧的8位字符串类型已变为bytes()。

最佳实践:

  • 文本数据使用PyUnicode
  • 二进制数据使用PyBytes
  • PyBytes和PyUnicode在3.0中不可互换
#include "bytesobject.h"  /* 提供PyBytes名称到PyString名称的映射 */
 
/* 文本示例 */
static PyObject * say_hello(PyObject *self, PyObject *args) {
    PyObject *name, *result;
    if (!PyArg_ParseTuple(args, "U:say_hello", &name))
        return NULL;
    result = PyUnicode_FromFormat("Hello, %S!", name);
    return result;
}
 
/* 二进制示例 */
static PyObject * encode_object(PyObject *self, PyObject *args) {
    char *encoded;
    PyObject *result, *myobj;
    if (!PyArg_ParseTuple(args, "O:encode_object", &myobj))
        return NULL;
    encoded = do_encode(myobj);
    if (encoded == NULL) return NULL;
    result = PyBytes_FromString(encoded);
    free(encoded);
    return result;
}

2.2 long/int统一

Python 3.0中只有一种整数类型。Python级别的int()对应2.x的long()类型。

迁移方案:

  • 使用intobject.h中PyInt_到PyLong_的别名
  • 某些情况下可使用抽象的PyNumber_* API
#include "intobject.h"
 
static PyObject * add_ints(PyObject *self, PyObject *args) {
    int one, two;
    PyObject *result;
    if (!PyArg_ParseTuple(args, "ii:add_ints", &one, &two))
        return NULL;
    return PyInt_FromLong(one + two);
}

3. 模块初始化和状态

Python 3.0改进了扩展模块初始化系统(参见PEP 3121)。

关键变更:

  • 模块状态应存储在解释器特定的结构中,而非全局变量
  • 使用PyModule_Create()替代Py_InitModule()
  • 需要实现traverse和clear函数以支持垃圾回收
struct module_state {
    PyObject *error;
};
 
#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
static struct module_state _state;
#endif

Python 3.0模块定义结构:

static struct PyModuleDef moduledef = {
    PyModuleDef_HEAD_INIT,
    "myextension",
    NULL,
    sizeof(struct module_state),
    myextension_methods,
    NULL,
    myextension_traverse,
    myextension_clear,
    NULL
};

初始化函数:

#if PY_MAJOR_VERSION >= 3
PyObject * PyInit_myextension(void)
#else
void initmyextension(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
    PyObject *module = PyModule_Create(&moduledef);
#else
    PyObject *module = Py_InitModule("myextension", myextension_methods);
#endif
    
    if (module == NULL) INITERROR;
    
    struct module_state *st = GETSTATE(module);
    st->error = PyErr_NewException("myextension.Error", NULL, NULL);
    if (st->error == NULL) {
        Py_DECREF(module);
        INITERROR;
    }
    
#if PY_MAJOR_VERSION >= 3
    return module;
#endif
}

4. 其他选项

对于新扩展模块开发,可考虑使用Cython:

  • 将Python-like语言翻译为C
  • 生成的扩展模块兼容Python 3.x和2.x

迁移检查清单

  1. 使用条件编译处理版本差异
  2. 用PyUnicode替代PyString处理文本
  3. 用PyBytes处理二进制数据
  4. 用PyLong_或PyInt_别名处理整数
  5. 模块状态存储改为解释器特定结构
  6. 实现traverse/clear支持GC
  7. 考虑使用Cython简化开发

知识关联