Документация Python неофициальный перевод

cporting.md

333 строк · 15.0 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.2/howto/cporting.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Перенос модулей расширения на Python 389| автор: | Benjamin Peterson |10| --- | --- |1112Аннотация1314Хотя изменение C-API не было целью Python 3, многие изменения на уровне Python сделали невозможным сохранение API Python 2 нетронутым. Фактически, некоторые изменения, такие как объединение [`int()`](https://python-all.ru/3.2/library/functions.html#int) и `long()`, более очевидны на уровне C. Этот документ стремится описать несовместимости и способы их обхода.1516## Условная компиляция1718Самый простой способ скомпилировать часть кода только для Python 3 – проверить, не меньше ли `PY_MAJOR_VERSION` 3.1920```c21#if PY_MAJOR_VERSION >= 322#define IS_PY3K23#endif24```2526Отсутствующие функции API можно заменить псевдонимами на их эквиваленты в условных блоках.2728## Изменения в API объектов2930Python 3 объединил некоторые типы со схожими функциями, чётко разделив другие.3132### Унификация str/unicode3334Тип [`str()`](https://python-all.ru/3.2/library/functions.html#str) в Python 3 (функции C `PyString_*`) эквивалентен типу `unicode()` в Python 2 (функции C `PyUnicode_*`). Старый 8-битный строковый тип стал [`bytes()`](https://python-all.ru/3.2/library/functions.html#bytes). Python 2.6 и более новые версии предоставляют заголовочный файл совместимости `bytesobject.h`, отображающий имена `PyBytes` на имена `PyString`. Для наилучшей совместимости с Python 3 для текстовых данных следует использовать `PyUnicode`, а для двоичных данных – `PyBytes`. Также важно помнить, что `PyBytes` и `PyUnicode` в Python 3 не являются взаимозаменяемыми, в отличие от `PyString` и `PyUnicode` в Python 2. Следующий пример показывает рекомендуемые подходы к работе с `PyUnicode`, `PyString` и `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 есть только один целочисленный тип – [`int()`](https://python-all.ru/3.2/library/functions.html#int). Но на самом деле он соответствует типу `long()` из Python 2 – тип [`int()`](https://python-all.ru/3.2/library/functions.html#int), использовавшийся в Python 2, был удалён. В C-API функции `PyInt_*` заменены их эквивалентами `PyLong_*`.7778Лучший подход здесь – использовать функции `PyInt_*` с псевдонимами `PyLong_*`, находящиеся в `intobject.h`. Абстрактные API `PyNumber_*` также можно использовать в некоторых случаях.7980```c81#include "Python.h"82#include "intobject.h"8384static PyObject *85add_ints(PyObject *self, PyObject *args) {86    int one, two;87    PyObject *result;8889    if (!PyArg_ParseTuple(args, "ii:add_ints", &one, &two))90        return NULL;9192    return PyInt_FromLong(one + two);93}94```9596## Инициализация и состояние модуля9798В Python 3 переработана система инициализации модулей расширения. (См. [**PEP 3121**](https://python-all.ru/3.2/howto/cporting.html).) Вместо хранения состояния модуля в глобальных переменных его следует хранить в структуре, специфичной для интерпретатора. Создание модулей, корректно работающих как в Python 2, так и в Python 3, нетривиально. Следующий простой пример показывает, как это сделать.99100```c101#include "Python.h"102103struct module_state {104    PyObject *error;105};106107#if PY_MAJOR_VERSION >= 3108#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))109#else110#define GETSTATE(m) (&_state)111static struct module_state _state;112#endif113114static PyObject *115error_out(PyObject *m) {116    struct module_state *st = GETSTATE(m);117    PyErr_SetString(st->error, "something bad happened");118    return NULL;119}120121static PyMethodDef myextension_methods[] = {122    {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},123    {NULL, NULL}124};125126#if PY_MAJOR_VERSION >= 3127128static int myextension_traverse(PyObject *m, visitproc visit, void *arg) {129    Py_VISIT(GETSTATE(m)->error);130    return 0;131}132133static int myextension_clear(PyObject *m) {134    Py_CLEAR(GETSTATE(m)->error);135    return 0;136}137138static struct PyModuleDef moduledef = {139        PyModuleDef_HEAD_INIT,140        "myextension",141        NULL,142        sizeof(struct module_state),143        myextension_methods,144        NULL,145        myextension_traverse,146        myextension_clear,147        NULL148};149150#define INITERROR return NULL151152PyObject *153PyInit_myextension(void)154155#else156#define INITERROR return157158void159initmyextension(void)160#endif161{162#if PY_MAJOR_VERSION >= 3163    PyObject *module = PyModule_Create(&moduledef);164#else165    PyObject *module = Py_InitModule("myextension", myextension_methods);166#endif167168    if (module == NULL)169        INITERROR;170    struct module_state *st = GETSTATE(module);171172    st->error = PyErr_NewException("myextension.Error", NULL, NULL);173    if (st->error == NULL) {174        Py_DECREF(module);175        INITERROR;176    }177178#if PY_MAJOR_VERSION >= 3179    return module;180#endif181}182```183184## CObject заменён на Capsule185186Объект `Capsule` был введён в Python 3.1 и 2.7 для замены `CObject`. CObject были полезны, но API `CObject` был проблематичным: он не позволял различать допустимые CObject, что позволяло несовпадающим CObject приводить к аварийному завершению интерпретатора, а некоторые его API полагались на неопределённое поведение в C. (Дополнительную информацию о причинах появления Capsules см. в [issue 5630](https://python-all.ru/3.2/howto/cporting.html).)187188Если в настоящее время используются CObject и требуется переход на 3.1 или новее, потребуется переключиться на Capsules. `CObject` был объявлен устаревшим в 3.1 и 2.7 и полностью удалён в Python 3.2. Если поддерживаются только версии 2.7, 3.1 и выше, можно просто переключиться на `Capsule`. Если требуется поддержка Python 3.0 или версий Python ранее 2.7, придётся поддерживать как CObject, так и Capsules. (Обратите внимание, что Python 3.0 больше не поддерживается и не рекомендуется для использования в производственной среде.)189190Следующий пример заголовочного файла `capsulethunk.h` может решить эту проблему. Для этого достаточно писать код с использованием API `капсулы` и подключать этот заголовочный файл после `Python.h`. Код будет автоматически использовать капсулы в версиях Python, где они доступны, и переключаться на CObject, когда капсулы недоступны.191192`capsulethunk.h` имитирует Capsules с помощью CObject. Однако `CObject` не предоставляет места для хранения «имени» капсулы. В результате имитируемые объекты `Capsule`, созданные `capsulethunk.h`, ведут себя несколько иначе, чем настоящие Capsules. А именно:193194> - Параметр name, передаваемый в [`PyCapsule_New()`](https://python-all.ru/3.2/c-api/capsule.html#PyCapsule_New), игнорируется.195> - Параметр name, передаваемый в [`PyCapsule_IsValid()`](https://python-all.ru/3.2/c-api/capsule.html#PyCapsule_IsValid) и [`PyCapsule_GetPointer()`](https://python-all.ru/3.2/c-api/capsule.html#PyCapsule_GetPointer), игнорируется, и проверка имени не выполняется.196> - [`PyCapsule_GetName()`](https://python-all.ru/3.2/c-api/capsule.html#PyCapsule_GetName) всегда возвращает NULL.197> - [`PyCapsule_SetName()`](https://python-all.ru/3.2/c-api/capsule.html#PyCapsule_SetName) всегда вызывает исключение и возвращает ошибку. (Поскольку в CObject нет способа хранить имя, явное сообщение об ошибке от [`PyCapsule_SetName()`](https://python-all.ru/3.2/c-api/capsule.html#PyCapsule_SetName) было сочтено предпочтительнее тихого провала. Если это неудобно, можно изменить локальную копию по своему усмотрению.)198199Файл `capsulethunk.h` можно найти в дистрибутиве исходного кода Python как [Doc/includes/capsulethunk.h](https://python-all.ru/src/3.2/Doc/includes/capsulethunk.h). Мы также включили его сюда для удобства.200201```c202#ifndef __CAPSULETHUNK_H203#define __CAPSULETHUNK_H204205#if (    (PY_VERSION_HEX <  0x02070000) \206     || ((PY_VERSION_HEX >= 0x03000000) \207      && (PY_VERSION_HEX <  0x03010000)) )208209#define __PyCapsule_GetField(capsule, field, default_value) \210    ( PyCapsule_CheckExact(capsule) \211        ? (((PyCObject *)capsule)->field) \212        : (default_value) \213    ) \214215#define __PyCapsule_SetField(capsule, field, value) \216    ( PyCapsule_CheckExact(capsule) \217        ? (((PyCObject *)capsule)->field = value), 1 \218        : 0 \219    ) \220221#define PyCapsule_Type PyCObject_Type222223#define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))224#define PyCapsule_IsValid(capsule, name) (PyCObject_Check(capsule))225226#define PyCapsule_New(pointer, name, destructor) \227    (PyCObject_FromVoidPtr(pointer, destructor))228229#define PyCapsule_GetPointer(capsule, name) \230    (PyCObject_AsVoidPtr(capsule))231232/* Не вызывайте PyCObject_SetPointer здесь, он завершится ошибкой, если есть деструктор */233#define PyCapsule_SetPointer(capsule, pointer) \234    __PyCapsule_SetField(capsule, cobject, pointer)235236#define PyCapsule_GetDestructor(capsule) \237    __PyCapsule_GetField(capsule, destructor)238239#define PyCapsule_SetDestructor(capsule, dtor) \240    __PyCapsule_SetField(capsule, destructor, dtor)241242/*243 * Извините, места просто нет244 * для хранения имени "name" Capsule в CObject.245 */246#define PyCapsule_GetName(capsule) NULL247248static int249PyCapsule_SetName(PyObject *capsule, const char *unused)250{251    unused = unused;252    PyErr_SetString(PyExc_NotImplementedError,253        "can't use PyCapsule_SetName with CObjects");254    return 1;255}256257#define PyCapsule_GetContext(capsule) \258    __PyCapsule_GetField(capsule, descr)259260#define PyCapsule_SetContext(capsule, context) \261    __PyCapsule_SetField(capsule, descr, context)262263static void *264PyCapsule_Import(const char *name, int no_block)265{266    PyObject *object = NULL;267    void *return_value = NULL;268    char *trace;269    size_t name_length = (strlen(name) + 1) * sizeof(char);270    char *name_dup = (char *)PyMem_MALLOC(name_length);271272    if (!name_dup) {273        return NULL;274    }275276    memcpy(name_dup, name, name_length);277278    trace = name_dup;279    while (trace) {280        char *dot = strchr(trace, '.');281        if (dot) {282            *dot++ = '\0';283        }284285        if (object == NULL) {286            if (no_block) {287                object = PyImport_ImportModuleNoBlock(trace);288            } else {289                object = PyImport_ImportModule(trace);290                if (!object) {291                    PyErr_Format(PyExc_ImportError,292                        "PyCapsule_Import could not "293                        "import module \"%s\"", trace);294                }295            }296        } else {297            PyObject *object2 = PyObject_GetAttrString(object, trace);298            Py_DECREF(object);299            object = object2;300        }301        if (!object) {302            goto EXIT;303        }304305        trace = dot;306    }307308    if (PyCObject_Check(object)) {309        PyCObject *cobject = (PyCObject *)object;310        return_value = cobject->cobject;311    } else {312        PyErr_Format(PyExc_AttributeError,313            "PyCapsule_Import \"%s\" is not valid",314            name);315    }316317EXIT:318    Py_XDECREF(object);319    if (name_dup) {320        PyMem_FREE(name_dup);321    }322    return return_value;323}324325#endif /* #if PY_VERSION_HEX < 0x02070000 */326327#endif /* __CAPSULETHUNK_H */328```329330## Другие варианты331332Если вы пишете новый модуль расширения, рассмотрите [Cython](https://python-all.ru/3.2/howto/cporting.html). Он транслирует язык, похожий на Python, в C. Создаваемые им модули расширения совместимы с Python 3 и Python 2.333