cporting.md
1> **Источник:** https://python-all.ru/3.7/howto/cporting.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Перенос модулей расширения на Python 389**автор**1011Benjamin Peterson1213Аннотация1415Хотя изменение C-API не было одной из целей Python 3, многочисленные изменения на уровне Python сделали невозможным сохранение API Python 2 нетронутым. На самом деле, некоторые изменения, такие как унификация [`int()`](https://python-all.ru/3.7/library/functions.html#int) и `long()`, более очевидны на уровне C. Этот документ стремится описать несовместимости и способы их обхода.1617## Условная компиляция1819Самый простой способ скомпилировать только часть кода для Python 3 – проверить, что `PY_MAJOR_VERSION` больше или равно 3.2021```c22#if PY_MAJOR_VERSION >= 323#define IS_PY3K24#endif25```2627Отсутствующие функции API можно заменить псевдонимами на их эквиваленты в условных блоках.2829## Изменения в API объектов3031Python 3 объединил некоторые типы со схожими функциями, чётко разделив другие.3233### Унификация str/unicode3435Тип [`str()`](https://python-all.ru/3.7/library/stdtypes.html#str) в Python 3 эквивалентен типу `unicode()` в Python 2; для обоих используются C-функции `PyUnicode_*`. Старый 8-битный строковый тип стал [`bytes()`](https://python-all.ru/3.7/library/stdtypes.html#bytes) с C-функциями `PyBytes_*`. Python 2.6 и выше предоставляют заголовочный файл совместимости `bytesobject.h`, отображающий имена `PyBytes` на `PyString`. Для наилучшей совместимости с Python 3 `PyUnicode` следует использовать для текстовых данных, а `PyBytes` для двоичных. Также важно помнить, что `PyBytes` и `PyUnicode` в Python 3 не взаимозаменяемы, как `PyString` и `PyUnicode` в Python 2. Следующий пример демонстрирует лучшие практики в отношении `PyUnicode`, `PyString`, и `PyBytes`.3637```c38#include "stdlib.h"39#include "Python.h"40#include "bytesobject.h"4142/* пример текста */43static PyObject *44say_hello(PyObject *self, PyObject *args) {45 PyObject *name, *result;4647 if (!PyArg_ParseTuple(args, "U:say_hello", &name))48 return NULL;4950 result = PyUnicode_FromFormat("Hello, %S!", name);51 return result;52}5354/* просто пересылка */55static char * do_encode(PyObject *);5657/* пример с байтами */58static PyObject *59encode_object(PyObject *self, PyObject *args) {60 char *encoded;61 PyObject *result, *myobj;6263 if (!PyArg_ParseTuple(args, "O:encode_object", &myobj))64 return NULL;6566 encoded = do_encode(myobj);67 if (encoded == NULL)68 return NULL;69 result = PyBytes_FromString(encoded);70 free(encoded);71 return result;72}73```7475### Унификация long/int7677В Python 3 есть только один целочисленный тип, [`int()`](https://python-all.ru/3.7/library/functions.html#int). Но на самом деле он соответствует типу `long()` из Python 2 – тип [`int()`](https://python-all.ru/3.7/library/functions.html#int), использовавшийся в Python 2, был удалён. В C-API функции `PyInt_*` заменены их эквивалентами `PyLong_*`.7879## Инициализация и состояние модуля8081В Python 3 переработана система инициализации модулей расширения. (См. [**PEP 3121**](https://python-all.ru/3.7/howto/cporting.html).) Вместо хранения состояния модуля в глобальных переменных его следует хранить в структуре, специфичной для интерпретатора. Создание модулей, корректно работающих как в Python 2, так и в Python 3, нетривиально. Следующий простой пример показывает, как это сделать.8283```c84#include "Python.h"8586struct module_state {87 PyObject *error;88};8990#if PY_MAJOR_VERSION >= 391#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))92#else93#define GETSTATE(m) (&_state)94static struct module_state _state;95#endif9697static PyObject *98error_out(PyObject *m) {99 struct module_state *st = GETSTATE(m);100 PyErr_SetString(st->error, "something bad happened");101 return NULL;102}103104static PyMethodDef myextension_methods[] = {105 {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},106 {NULL, NULL}107};108109#if PY_MAJOR_VERSION >= 3110111static int myextension_traverse(PyObject *m, visitproc visit, void *arg) {112 Py_VISIT(GETSTATE(m)->error);113 return 0;114}115116static int myextension_clear(PyObject *m) {117 Py_CLEAR(GETSTATE(m)->error);118 return 0;119}120121static struct PyModuleDef moduledef = {122 PyModuleDef_HEAD_INIT,123 "myextension",124 NULL,125 sizeof(struct module_state),126 myextension_methods,127 NULL,128 myextension_traverse,129 myextension_clear,130 NULL131};132133#define INITERROR return NULL134135PyMODINIT_FUNC136PyInit_myextension(void)137138#else139#define INITERROR return140141void142initmyextension(void)143#endif144{145#if PY_MAJOR_VERSION >= 3146 PyObject *module = PyModule_Create(&moduledef);147#else148 PyObject *module = Py_InitModule("myextension", myextension_methods);149#endif150151 if (module == NULL)152 INITERROR;153 struct module_state *st = GETSTATE(module);154155 st->error = PyErr_NewException("myextension.Error", NULL, NULL);156 if (st->error == NULL) {157 Py_DECREF(module);158 INITERROR;159 }160161#if PY_MAJOR_VERSION >= 3162 return module;163#endif164}165```166167## CObject заменён на Capsule168169Объект `Capsule` был представлен в Python 3.1 и 2.7 для замены `CObject`. Объекты CObject были полезны, но API `CObject` был проблематичным: он не позволял различать корректные CObject, что при несоответствии CObject приводило к аварийному завершению интерпретатора, а некоторые его API полагались на неопределённое поведение в C. (Для дополнительного чтения о причинах появления капсул см. [bpo-5630](https://python-all.ru/3.7/howto/cporting.html).)170171Если вы в настоящее время используете CObject и хотите перейти на Python 3.1 или новее, вам нужно переключиться на капсулы. `CObject` был объявлен устаревшим в Python 3.1 и 2.7 и полностью удалён в Python 3.2. Если вы поддерживаете только Python 2.7 или Python 3.1 и выше, вы можете просто переключиться на `Capsule`. Если вам нужно поддерживать Python 3.0 или версии Python, предшествующие 2.7, вам придётся поддерживать и CObject, и капсулы. (Обратите внимание, что Python 3.0 больше не поддерживается и не рекомендуется для использования в производственной среде.)172173Следующий пример заголовочного файла `capsulethunk.h` может решить проблему. Просто пишите свой код, используя API `Capsule`, и включайте этот заголовочный файл после `Python.h`. Ваш код будет автоматически использовать капсулы в версиях Python, где они есть, и переключаться на CObject, когда капсулы недоступны.174175`capsulethunk.h` имитирует капсулы с помощью CObject. Однако, `CObject` не предоставляет места для хранения «имени» капсулы. В результате имитируемые объекты `Capsule`, создаваемые `capsulethunk.h`, ведут себя немного иначе, чем настоящие капсулы. В частности:176177> - Параметр name, передаваемый в [`PyCapsule_New()`](https://python-all.ru/3.7/c-api/capsule.html#c.PyCapsule_New), игнорируется.178> - Параметр name, передаваемый в [`PyCapsule_IsValid()`](https://python-all.ru/3.7/c-api/capsule.html#c.PyCapsule_IsValid) и [`PyCapsule_GetPointer()`](https://python-all.ru/3.7/c-api/capsule.html#c.PyCapsule_GetPointer), игнорируется, и проверка имени на ошибки не выполняется.179> - [`PyCapsule_GetName()`](https://python-all.ru/3.7/c-api/capsule.html#c.PyCapsule_GetName) всегда возвращает NULL.180> - [`PyCapsule_SetName()`](https://python-all.ru/3.7/c-api/capsule.html#c.PyCapsule_SetName) всегда возбуждает исключение и возвращает признак ошибки. (Поскольку нет способа сохранить имя в CObject, было решено, что явное сообщение об ошибке при [`PyCapsule_SetName()`](https://python-all.ru/3.7/c-api/capsule.html#c.PyCapsule_SetName) здесь предпочтительнее молчаливого отказа. Если это неудобно, вы можете изменить свою локальную копию по своему усмотрению.)181182Вы можете найти `capsulethunk.h` в дистрибутиве исходных кодов Python как [Doc/includes/capsulethunk.h](https://python-all.ru/src/3.7/Doc/includes/capsulethunk.h). Мы также включили его сюда для вашего удобства:183184```c185#ifndef __CAPSULETHUNK_H186#define __CAPSULETHUNK_H187188#if ( (PY_VERSION_HEX < 0x02070000) \189 || ((PY_VERSION_HEX >= 0x03000000) \190 && (PY_VERSION_HEX < 0x03010000)) )191192#define __PyCapsule_GetField(capsule, field, default_value) \193 ( PyCapsule_CheckExact(capsule) \194 ? (((PyCObject *)capsule)->field) \195 : (default_value) \196 ) \197198#define __PyCapsule_SetField(capsule, field, value) \199 ( PyCapsule_CheckExact(capsule) \200 ? (((PyCObject *)capsule)->field = value), 1 \201 : 0 \202 ) \203204#define PyCapsule_Type PyCObject_Type205206#define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))207#define PyCapsule_IsValid(capsule, name) (PyCObject_Check(capsule))208209#define PyCapsule_New(pointer, name, destructor) \210 (PyCObject_FromVoidPtr(pointer, destructor))211212#define PyCapsule_GetPointer(capsule, name) \213 (PyCObject_AsVoidPtr(capsule))214215/* Не вызывайте PyCObject_SetPointer здесь, он завершится ошибкой, если есть деструктор */216#define PyCapsule_SetPointer(capsule, pointer) \217 __PyCapsule_SetField(capsule, cobject, pointer)218219#define PyCapsule_GetDestructor(capsule) \220 __PyCapsule_GetField(capsule, destructor)221222#define PyCapsule_SetDestructor(capsule, dtor) \223 __PyCapsule_SetField(capsule, destructor, dtor)224225/*226 * Извините, места просто нет227 * для хранения имени "name" Capsule в CObject.228 */229#define PyCapsule_GetName(capsule) NULL230231static int232PyCapsule_SetName(PyObject *capsule, const char *unused)233{234 unused = unused;235 PyErr_SetString(PyExc_NotImplementedError,236 "can't use PyCapsule_SetName with CObjects");237 return 1;238}239240#define PyCapsule_GetContext(capsule) \241 __PyCapsule_GetField(capsule, descr)242243#define PyCapsule_SetContext(capsule, context) \244 __PyCapsule_SetField(capsule, descr, context)245246static void *247PyCapsule_Import(const char *name, int no_block)248{249 PyObject *object = NULL;250 void *return_value = NULL;251 char *trace;252 size_t name_length = (strlen(name) + 1) * sizeof(char);253 char *name_dup = (char *)PyMem_MALLOC(name_length);254255 if (!name_dup) {256 return NULL;257 }258259 memcpy(name_dup, name, name_length);260261 trace = name_dup;262 while (trace) {263 char *dot = strchr(trace, '.');264 if (dot) {265 *dot++ = '\0';266 }267268 if (object == NULL) {269 if (no_block) {270 object = PyImport_ImportModuleNoBlock(trace);271 } else {272 object = PyImport_ImportModule(trace);273 if (!object) {274 PyErr_Format(PyExc_ImportError,275 "PyCapsule_Import could not "276 "import module \"%s\"", trace);277 }278 }279 } else {280 PyObject *object2 = PyObject_GetAttrString(object, trace);281 Py_DECREF(object);282 object = object2;283 }284 if (!object) {285 goto EXIT;286 }287288 trace = dot;289 }290291 if (PyCObject_Check(object)) {292 PyCObject *cobject = (PyCObject *)object;293 return_value = cobject->cobject;294 } else {295 PyErr_Format(PyExc_AttributeError,296 "PyCapsule_Import \"%s\" is not valid",297 name);298 }299300EXIT:301 Py_XDECREF(object);302 if (name_dup) {303 PyMem_FREE(name_dup);304 }305 return return_value;306}307308#endif /* #if PY_VERSION_HEX < 0x02070000 */309310#endif /* __CAPSULETHUNK_H */311```312313## Другие варианты314315Если вы пишете новый модуль расширения, рассмотрите [Cython](https://python-all.ru/3.7/howto/cporting.html). Он транслирует язык, похожий на Python, в C. Создаваемые им модули расширения совместимы с Python 3 и Python 2.316