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;
#endifPython 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
迁移检查清单
- 使用条件编译处理版本差异
- 用PyUnicode替代PyString处理文本
- 用PyBytes处理二进制数据
- 用PyLong_或PyInt_别名处理整数
- 模块状态存储改为解释器特定结构
- 实现traverse/clear支持GC
- 考虑使用Cython简化开发
知识关联
- 参见Python高级编程-函数式工具了解现代Python扩展开发
- 与C程序设计语言-第11章-运算符重载形成对照:C扩展开发 vs 面向对象设计