Содержание страницы
Портирование модулей расширения на 3.0¶Porting Extension Modules to 3.0
| автор: | Benjamin Peterson |
|---|
Аннотация
Хотя изменение C-API не входило в цели Python 3.0, многочисленные изменения на уровне Python сделали невозможным сохранение API версии 2.x нетронутым. Фактически, некоторые изменения, такие как унификация int() и long(), более очевидны на уровне C. Данный документ стремится описать несовместимости и способы их обхода.
Условная компиляция¶Conditional compilation
Самый простой способ компилировать только часть кода для 3.0 – проверить, что PY_MAJOR_VERSION больше или равно 3.
#if PY_MAJOR_VERSION >= 3
#define IS_PY3K
#endif
Отсутствующие функции API можно заменить псевдонимами на их эквиваленты в условных блоках.
Изменения в API объектов¶Changes to Object APIs
Python 3.0 объединил некоторые типы со схожими функциями, чётко разделив другие.
Унификация str/unicode¶str/unicode Unification
Тип str() в Python 3.0 (функции PyString_* в C) эквивалентен типу\nunicode() (PyUnicode_*) в версии 2.x. Старый 8-битный строковый тип стал\nbytes(). Python 2.6 и новее предоставляют заголовочный файл совместимости,\nbytesobject.h, который отображает имена PyBytes на имена PyString. Для наилучшей совместимости с 3.0,\nPyUnicode следует использовать для текстовых данных, а\nPyBytes – для двоичных. Также важно помнить, что\nPyBytes и PyUnicode в 3.0 не взаимозаменяемы, в отличие от\nPyString и PyString в 2.x. Следующий пример демонстрирует\nлучшие практики в отношении PyUnicode, PyString и\nPyBytes.
#include "stdlib.h"
#include "Python.h"
#include "bytesobject.h"
/* пример текста */
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 char * do_encode(PyObject *);
/* пример с байтами */
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;
}
Унификация long/int¶long/int Unification
В Python 3.0 есть только один целочисленный тип. Он называется int() на\nуровне Python, но на самом деле соответствует типу long() из 2.x. В\nC-API функции PyInt_* заменены их соседями PyLong_*. Лучший\nспособ действий – использовать функции PyInt_*, псевдонимы для\nкоторых PyLong_* находятся в intobject.h. Абстрактные API PyNumber_*\nтакже можно использовать в некоторых случаях.
#include "Python.h"
#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);
}
Инициализация и состояние модуля¶Module initialization and state
Python 3.0 имеет переработанную систему инициализации модулей расширения. (См. PEP PEP 3121.) Вместо хранения состояния модуля в глобальных переменных, его следует хранить в структуре, специфичной для интерпретатора. Создание модулей, правильно работающих как в 2.x, так и в 3.0, – непростая задача. Следующий простой пример демонстрирует, как это сделать.
#include "Python.h"
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
static PyObject *
error_out(PyObject *m) {
struct module_state *st = GETSTATE(m);
PyErr_SetString(st->error, "something bad happened");
return NULL;
}
static PyMethodDef myextension_methods[] = {
{"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
{NULL, NULL}
};
#if PY_MAJOR_VERSION >= 3
static int myextension_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int myextension_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"myextension",
NULL,
sizeof(struct module_state),
myextension_methods,
NULL,
myextension_traverse,
myextension_clear,
NULL
};
#define INITERROR return NULL
PyObject *
PyInit_myextension(void)
#else
#define INITERROR return
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
}