cporting.md
1> **Источник:** https://python-all.ru/3.0/howto/cporting.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Портирование модулей расширения на 3.089| автор: | Benjamin Peterson |10| --- | --- |1112Аннотация1314Хотя изменение C-API не входило в цели Python 3.0, многочисленные изменения на уровне Python сделали невозможным сохранение API версии 2.x нетронутым. Фактически, некоторые изменения, такие как унификация [`int()`](https://python-all.ru/3.0/library/functions.html#int) и `long()`, более очевидны на уровне C. Данный документ стремится описать несовместимости и способы их обхода.1516## Условная компиляция1718Самый простой способ компилировать только часть кода для 3.0 – проверить, что `PY_MAJOR_VERSION` больше или равно 3.1920```c21#if PY_MAJOR_VERSION >= 322#define IS_PY3K23#endif24```2526Отсутствующие функции API можно заменить псевдонимами на их эквиваленты в условных блоках.2728## Изменения в API объектов2930Python 3.0 объединил некоторые типы со схожими функциями, чётко разделив другие.3132### Унификация str/unicode3334Тип [`str()`](https://python-all.ru/3.0/library/functions.html#str) в Python 3.0 (функции `PyString_*` в C) эквивалентен типу\\n`unicode()` (`PyUnicode_*`) в версии 2.x. Старый 8-битный строковый тип стал\\n[`bytes()`](https://python-all.ru/3.0/library/functions.html#bytes). Python 2.6 и новее предоставляют заголовочный файл совместимости,\\n`bytesobject.h`, который отображает имена `PyBytes` на имена `PyString`. Для наилучшей совместимости с 3.0,\\n`PyUnicode` следует использовать для текстовых данных, а\\n`PyBytes` – для двоичных. Также важно помнить, что\\n`PyBytes` и `PyUnicode` в 3.0 не взаимозаменяемы, в отличие от\\n`PyString` и `PyString` в 2.x. Следующий пример демонстрирует\\nлучшие практики в отношении `PyUnicode`, `PyString` и\\n`PyBytes`.3536```c37#include "stdlib.h"38#include "Python.h"39#include "bytesobject.h"4041/* пример текста */42static PyObject *43say_hello(PyObject *self, PyObject *args) {44 PyObject *name, *result;4546 if (!PyArg_ParseTuple(args, "U:say_hello", &name))47 return NULL;4849 result = PyUnicode_FromFormat("Hello, %S!", name);50 return result;51}5253/* просто пересылка */54static char * do_encode(PyObject *);5556/* пример с байтами */57static PyObject *58encode_object(PyObject *self, PyObject *args) {59 char *encoded;60 PyObject *result, *myobj;6162 if (!PyArg_ParseTuple(args, "O:encode_object", &myobj))63 return NULL;6465 encoded = do_encode(myobj);66 if (encoded == NULL)67 return NULL;68 result = PyBytes_FromString(encoded);69 free(encoded);70 return result;71}72```7374### Унификация long/int7576В Python 3.0 есть только один целочисленный тип. Он называется [`int()`](https://python-all.ru/3.0/library/functions.html#int) на\\nуровне Python, но на самом деле соответствует типу `long()` из 2.x. В\\nC-API функции `PyInt_*` заменены их соседями `PyLong_*`. Лучший\\nспособ действий – использовать функции `PyInt_*`, псевдонимы для\\nкоторых `PyLong_*` находятся в `intobject.h`. Абстрактные API `PyNumber_*`\\nтакже можно использовать в некоторых случаях.7778```c79#include "Python.h"80#include "intobject.h"8182static PyObject *83add_ints(PyObject *self, PyObject *args) {84 int one, two;85 PyObject *result;8687 if (!PyArg_ParseTuple(args, "ii:add_ints", &one, &two))88 return NULL;8990 return PyInt_FromLong(one + two);91}92```9394## Инициализация и состояние модуля9596Python 3.0 имеет переработанную систему инициализации модулей расширения. (См. PEP [**PEP 3121**](https://python-all.ru/3.0/howto/cporting.html).) Вместо хранения состояния модуля в глобальных переменных, его следует хранить в структуре, специфичной для интерпретатора. Создание модулей, правильно работающих как в 2.x, так и в 3.0, – непростая задача. Следующий простой пример демонстрирует, как это сделать.9798```c99#include "Python.h"100101struct module_state {102 PyObject *error;103};104105#if PY_MAJOR_VERSION >= 3106#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))107#else108#define GETSTATE(m) (&_state)109static struct module_state _state;110#endif111112static PyObject *113error_out(PyObject *m) {114 struct module_state *st = GETSTATE(m);115 PyErr_SetString(st->error, "something bad happened");116 return NULL;117}118119static PyMethodDef myextension_methods[] = {120 {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},121 {NULL, NULL}122};123124#if PY_MAJOR_VERSION >= 3125126static int myextension_traverse(PyObject *m, visitproc visit, void *arg) {127 Py_VISIT(GETSTATE(m)->error);128 return 0;129}130131static int myextension_clear(PyObject *m) {132 Py_CLEAR(GETSTATE(m)->error);133 return 0;134}135136static struct PyModuleDef moduledef = {137 PyModuleDef_HEAD_INIT,138 "myextension",139 NULL,140 sizeof(struct module_state),141 myextension_methods,142 NULL,143 myextension_traverse,144 myextension_clear,145 NULL146};147148#define INITERROR return NULL149150PyObject *151PyInit_myextension(void)152153#else154#define INITERROR return155156void157initmyextension(void)158#endif159{160#if PY_MAJOR_VERSION >= 3161 PyObject *module = PyModule_Create(&moduledef);162#else163 PyObject *module = Py_InitModule("myextension", myextension_methods);164#endif165166 if (module == NULL)167 INITERROR;168 struct module_state *st = GETSTATE(module);169170 st->error = PyErr_NewException("myextension.Error", NULL, NULL);171 if (st->error == NULL) {172 Py_DECREF(module);173 INITERROR;174 }175176#if PY_MAJOR_VERSION >= 3177 return module;178#endif179}180```181182## Другие варианты183184Если вы пишете новый модуль расширения, возможно, стоит рассмотреть [Cython](https://python-all.ru/3.0/howto/cporting.html). Он транслирует язык, похожий на Python, в C. Создаваемые им модули расширения совместимы с Python 3.x и 2.x.185