Главная страница
Навигация по странице:

  • Компилирование и упаковывание расширений

  • Формат Тип в языке Python Тип аргумента в языке C

  • справочник по Python. мм isbn 9785932861578 9 785932 861578


    Скачать 4.21 Mb.
    Названиемм isbn 9785932861578 9 785932 861578
    Анкорсправочник по Python
    Дата08.05.2022
    Размер4.21 Mb.
    Формат файлаpdf
    Имя файлаBizli_Python-Podrobnyy-spravochnik.440222.pdf
    ТипСправочник
    #518195
    страница66 из 82
    1   ...   62   63   64   65   66   67   68   69   ...   82
    738
    Глава 26. Расширение и встраивание интерпретатора Python строку). Если этот шаг пропустить, функция-обертка нарушит принцип неизменяемости строк, который действует в языке Python.
    Если необходимо возбудить исключение, для этого следует вызвать функ- цию PyExc_SetString(), как это сделано в функции-обертке py_distance().
    Возвращаемое значение NULL служит сигналом о возникшей ошибке.
    Таблица методов _examplemethods используется для связи имен в языке Py-
    Py- thon с функциями-обертками на языке C. Эти имена используются для вы- с функциями-обертками на языке C. Эти имена используются для вы-
    C. Эти имена используются для вы-
    . Эти имена используются для вы- зова функций из интерпретатора. Флаг METH_VARARGS указывает на то, какое соглашение о вызове применяется к функции-обертке. В данном случае функция-обертка принимает только позиционные аргументы в виде кор- тежа. В качестве значения флага может также передаваться комбинация
    METH_VARARGS
    | METH_KEYWORDS, которая указывает, что функция-обертка при- нимает также именованные аргументы. Дополнительно при создании та- блицы методов устанавливаются строки документирования для каждой функции-обертки.
    В заключительной части модуля расширения выполняется процедура ини- циализации, которая отличается для Python 2 и Python 3. В Python 2 для инициализации содержимого модуля используется функция инициали- зации init_example. В данном примере вызов функции Py_InitModule(“_ex-
    _InitModule(“_ex-
    InitModule(“_ex-
    (“_ex- ex- ample”,_examplemethods)
    создает модуль с именем _example и заполняет его объектами функций, соответствующих функциям, перечисленным в та- блице методов. В Python 3 сначала необходимо создать объект _examplemod- examplemod- ule класса PyModuleDef, описывающий модуль. Затем требуется написать функцию PyInit__example(), которая инициализирует модуль, как показано в примере. Кроме того, функция инициализации также является местом, где определяются значения констант и другие элементы модуля. Напри- мер, функция PyModule_AddIntMacro() добавляет в модуль значение препро- цессора.
    Следует отметить, что соглашение об именовании имеет критически важ- ное значение для процедуры инициализации модуля. Если создается мо- дуль с именем modname, в Python 2 функция инициализации модуля должна иметь имя initmodname(), а в Python 3 – имя PyInit_modname(). Если не сле- довать этому соглашению, интерпретатор не сможет корректно загрузить модуль.
    Выбор имен для модулей расширений
    Стандартной практикой стало давать модулям расширений на языке C име-
    C име- име- на, начинающиеся с символа подчеркивания, такие как ‘_example’. Данное соглашение соблюдается и в самой стандартной библиотеке Python. На-
    Python. На-
    . На- пример, существуют модули _socket, _thread, _sre и _fileio, соответствую- щие программным компонентам на языке C модулей socket, threading, re и io. На практике модули расширений на языке C обычно не используются непосредственно. Для взаимодействия с ними создаются высокоуровневые модули на языке Python, например такие, как показано ниже:
    # example.py from _example import *

    Модули расширений
    739
    # Далее следует дополнительный программный код поддержки
    ...
    Назначение такого модуля-обертки на языке Python состоит в том, чтобы обеспечить дополнительную поддержку для вашего модуля или предоста- вить более высокоуровневый интерфейс. Во многих случаях реализовать определенные части модуля расширения проще на языке Python, чем на C.
    Выбор такой архитектуры позволяет упростить решение этой задачи. Мно- гие модули, входящие в состав стандартной библиотеки, представляют со- бой подобную смесь программного кода на языках C и Python.
    Компилирование и упаковывание расширений
    Предпочтительным механизмом компиляции и упаковки модулей расши- рений является пакет distutils. Чтобы воспользоваться им, необходимо создать файл setup.py, который выглядит, как показано ниже:
    # setup.py from distutils.core import setup, Extension
    ёёё
    setup(name=”example”,
    version=”1.0”,
    py_modules = [‘example.py’],
    ext_modules = [
    Extension(“_example”,
    [“pyexample.c”,”example.c”])
    ]
    )
    В этом файле требовалось подключить файл с высокоуровневым модулем на языке Python (example.py) и исходные файлы, составляющие модуль рас- ширения (pyexample.c, example.c). Чтобы собрать модуль для тестирования, нужно ввести команду:
    % python setup.py build_ext --inplace
    Она скомпилирует файлы с исходными текстами в разделяемую библиоте- ку и оставит ее в текущем рабочем каталоге. Эта библиотека получит имя
    _examplemodule.so
    , _examplemodule.pyd или другое аналогичное имя.
    После успешной компиляции использование модуля выглядит очень про- сто. Например:
    % python3.0
    Python 3.0 (r30:67503, Dec 4 2008, 09:40:15)
    [GCC 4.0.1 (Apple Inc. build 5465)] on darwin
    Type “help”, “copyright”, “credits” or “license” for more information.
    >>> import example
    >>> example.gcd(78,120)
    6
    >>> example.replace(“Hello World”,’ ‘,’-’)
    (1, ‘Hello-World’)
    >>> example.distance()
    Traceback (most recent call last):
    File “”, line 1, in

    740
    Глава 26. Расширение и встраивание интерпретатора Python
    NotImplementedError: distance() not implemented.
    (Перевод:
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 1, в
    NotImplementedError: функция distance() не реализована
    )
    >>>
    Для сборки более сложных модулей расширения может потребоваться указать дополнительную информацию, например подключаемые каталоги и библиотеки и макроопределения препроцессора. Эту информацию также можно добавить в файл setup.py, как показано ниже:
    # setup.py from distutils.core import setup, Extension
    ёёё
    setup(name=”example”,
    version=”1.0”,
    py_modules = [‘example.py’],
    ext_modules = [
    Extension(“_example”,
    [“pyexample.c”,”example.c”],
    include_dirs = [“/usr/include/X11”,”/opt/include”],
    define_macros = [(‘DEBUG’,1’),
    (‘MONDO_FLAG’,1)],
    undef_macros = [‘HAVE_FOO’,’HAVE_NOT’],
    library_dirs= [“/usr/lib/X11”, “/opt/lib”],
    libraries = [ “X11”, “Xt”, “blah” ])
    ]
    )
    Чтобы установить модуль для общего пользования, достаточно просто вве- сти команду python setup.py install. Дополнительные подробности по этой теме приводятся в главе 8 «Модули, пакеты и дистрибутивы».
    В некоторых ситуациях может появиться необходимость собрать модуль расширения вручную. Для этого практически всегда требуется дополни- тельно иметь представление о различных параметрах компиляции и ком- поновки. Ниже приводится пример сборки модуля в Linux:
    linux % gcc -c -fpic -I/usr/local/include/python2.6 example.c pyexample.c
    linux % gcc -shared example.o pyexample.o -o _examplemodule.so
    Преобразование типов данных языка Python
    в типы языка C
    Ниже перечислены функции, которые используются модулями расшире- ний для преобразования типов аргументов при передаче из программно- го кода на языке Python в программный код на языке C. Прототипы этих функций определены в заголовочном файле Python.h.
    int PyArg_ParseTuple(PyObject *args, char *format, ...);
    Преобразует кортеж args позиционных аргументов в последовательность переменных на языке C. В аргументе format передается строка формата,

    Модули расширений
    741
    содержащая ноль или более спецификаторов, которые приводятся в табл.
    26.1–26.3, описывающих ожидаемое содержимое args. Все остальные ар- гументы содержат адреса переменных языка C, куда будут помещаться результаты преобразования. Порядок и типы аргументов должны соответ- ствовать спецификаторам в строке format. Возвращает ноль, если не уда- лось преобразовать аргументы.
    int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kwargs, char *format,
    char **kwlist, ...);
    Преобразует кортеж args с позиционными аргументами и словарь kwargs с именованными аргументами. Аргумент format имеет тот же смысл, что и в функции PyArg_ParseTuple(). Единственное отличие состоит в том, что ар- гумент kwlist является списком строк, оканчивающимся нулевым симво- лом и содержащим имена всех аргументов. В случае успеха возвращает 1, в случае ошибки – 0.
    В табл. 26.1 перечислены спецификаторы формата, которые можно исполь- табл. 26.1 перечислены спецификаторы формата, которые можно исполь- табл. 26.1 перечислены спецификаторы формата, которые можно исполь-
    . 26.1 перечислены спецификаторы формата, которые можно исполь-
    26.1 перечислены спецификаторы формата, которые можно исполь- зовать в аргументе format для преобразования числовых значений. В колон- ке «Тип аргумента в языке C» указывается тип аргумента, который должен передаваться функциям PyArg_Parse*(). Для чисел – это всегда указатель на область в памяти, куда должен быть сохранен результат.
    Таблица 26.1. Преобразование чисел и соответствующие типы
    аргументов функций PyArg_Parse*
    Формат
    Тип в языке Python
    Тип аргумента в языке C
    “b”
    Целое число signed char *
    r
    “B”
    Целое число unsigned char *
    r
    “h”
    Целое число short *
    r
    “H”
    Целое число unsigned short *
    r
    “I”
    Целое число int *
    r
    “I”
    Целое число unsigned int *
    r
    “l”
    Целое число long int *
    r
    “k”
    Целое число unsigned long *
    r
    “L”
    Целое число long long *
    r
    “K”
    Целое число unsigned long long *
    r
    “n”
    Целое число
    Py_ssize_t *
    r
    “f”
    Число с плавающей точкой float *
    r
    “d”
    Число с плавающей точкой double *
    r
    “D”
    Комплексное число
    Py_complex *
    r
    Если при преобразовании целого числа со знаком значение, полученное из программного кода на языке Python, окажется слишком большим, чтобы уместиться в переменную с указанным типом языка C, будет возбуждено

    742
    Глава 26. Расширение и встраивание интерпретатора Python исключение OverflowError. Однако при преобразованиях целых чисел без знака (таких как ‘I’, ‘H’, ‘K’ и других) проверка на переполнение не выпол- няется и слишком большие значения будут просто усечены. При преобра- зовании в числа с плавающей точкой во входных аргументах могут пере- даваться значения типов int или float языка Python. В этом случае целые числа будут преобразованы в числа с плавающей точкой. В качестве чисел допускается передавать экземпляры пользовательских классов, при усло- вии, что они предоставляют соответствующие методы преобразования, та- кие как __int__() или __float__(). Например, экземпляр класса, реализую- щий метод __int__(), может передаваться любой из перечисленных выше операций целочисленных преобразований (при этом метод __int__() будет вызван автоматически).
    В табл. 26.2 перечислены спецификаторы формата, которые применяются к строкам и байтам. Многие операции преобразования возвращают в ре- зультате указатель и длину строки.
    Таблица 26.2. Преобразование строк и соответствующие типы
    аргументов функций PyArg_Parse*
    Формат
    Тип в языке Python
    Тип аргумента в языке C
    “с”
    Строка или строка байтов с длиной
    1
    char *
    r
    “s”
    Строка char **
    r
    “s#”
    Строка, строка байтов или буфер char **
    r, int *len
    “s*”
    Строка, строка байтов или буфер
    Py_buffer *
    r
    “z”
    Строка или None char **
    r
    “z#”
    Строка, строка байтов или None char **
    r, int *len
    “z*”
    Строка, строка байтов, буфер или
    None
    Py_buffer *
    r
    “y”
    Строка байтов (оканчивающаяся нулевым символом)
    char **
    r
    “y#”
    Строка байтов char **
    r, int *len
    “y*”
    Строка байтов или буфер
    Py_buffer *
    r
    “u”
    Строка (Юникода)
    Py_UNICODE **
    r
    “u#”
    Строка (Юникода)
    Py_UNICODE **
    r, int *len
    “es”
    Строка const char *
    enc, char **r
    “es#”
    Строка или строка байтов const char *
    enc, char **r, int *len
    “et”
    Строка или строка байтов (оканчи- вающаяся нулевым символом)
    const char *
    enc, char **r, int *len
    “et#”
    Строка или строка байтов const char *
    enc, char **r, int *len
    “t#”
    Буфер, доступный только для чте- ния char **
    r, int *len

    Модули расширений
    743
    Формат
    Тип в языке Python
    Тип аргумента в языке C
    “w”
    Б
    уфер, доступный для чтения/за- писи char **
    r
    “w#”
    Буфер, доступный для чтения/за- писи char **
    r, int *len
    “w*”
    Буфер, доступный для чтения/за- писи
    Py_buffer *
    r
    Обработка строк в расширениях на языке C представляет отдельную про-
    C представляет отдельную про- представляет отдельную про- блему, потому что тип данных char * используется для самых разных нужд.
    Например, указатель этого типа может ссылаться на текст, на одиночный символ или на буфер с двоичными данными. Еще одна проблема обуслов- лена тем, что в языке C для обозначения конца строки используется символ
    NULL
    (‘\x00’).
    При передаче текста должны использоваться спецификаторы “s”, “z”, “u”,
    “es”
    и “et”, представленные в табл. 26.2. Эти спецификаторы не предпола-
    26.2. Эти спецификаторы не предпола-
    Эти спецификаторы не предпола- гают, что входной текст содержит завершающий символ NULL; в этом слу- чае будет возбуждено исключение TypeError. Однако в программном коде на языке C можно смело полагаться на то, что строки будут завершаться символом NULL. В Python 2 допускается передавать как строки 8-битовых символов, так и строки Юникода, но в Python 3 все спецификаторы, за ис-
    Python 3 все спецификаторы, за ис-
    3 все спецификаторы, за ис- ключением “et”, предполагают получить данные типа str языка Python и не могут использоваться для преобразования строк байтов. Когда строки
    Юникода передаются программному коду на языке C, они всегда кодиру-
    C, они всегда кодиру-
    , они всегда кодиру- ются с применением кодировки, используемой интерпретатором по умол- чанию (обычно UTF-8). Единственное исключение составляет специфика-
    (обычно UTF-8). Единственное исключение составляет специфика- обычно UTF-8). Единственное исключение составляет специфика-
    UTF-8). Единственное исключение составляет специфика-
    Единственное исключение составляет специфика- тор “u”, который возвращает строку Юникода во внутреннем представле- нии, используемом в языке Python. Это массив значений типа Py_UNICODE, где символы Юникода обычно представлены типом wchar_t языка C.
    Спецификаторы “es” и “et” позволяют определить альтернативную коди- ровку текста. Для этих спецификаторов требуется указать название коди- ровки, такое как ‘utf-8’ или ‘iso-8859-1’, и текст будет преобразован в ука- занный формат и возвращен в виде буфера. Отличие спецификатора “et” от
    “es”
    заключается в том, что при передаче строки байтов предполагается, что строка уже была закодирована и передается дальше в исходном виде.
    Важно помнить, что при использовании спецификаторов “es” и “et” па- мять для хранения результата выделяется динамически и ее необходимо явно освобождать вызовом функции PyMem_Free(). То есть программный код, использующий эти два вида преобразования, должен выглядеть при- мерно так:
    PyObject *py_wrapper(PyObject *self, PyObject *args) {
    char *buffer;
    if (!PyArg_ParseTuple(args,”es”,”utf-8”,&buffer)) {
    return NULL;
    }
    /* Выполнить какие-либо операции. */
    ...

    744
    Глава 26. Расширение и встраивание интерпретатора Python
    /* Освободить память и вернуть результат */
    PyMem_Free(buffer);
    return result;
    }
    Для обработки текста или двоичных данных используются спецификато- ры “s#”, “z#”, “u#”, “es#” или “et#”. Эти спецификаторы действуют точно так же, как и описанные выше, за исключением того, что дополнительно они возвращают длину. Благодаря этому снимается ограничение на использо- вание символа NULL. Кроме того, эти виды преобразований обеспечивают возможность работы со строками байтов и с любыми другими объектами, поддерживающими интерфейс буферов. Интерфейс буфера обеспечивает средства представления объектов в языке Python в виде простых двоичных буферов с содержимым этих объектов. Обычно этот интерфейс поддержи- вается строками, строками байтов и массивами (например, массивы, соз- данные средствами модуля array, поддерживают этот интерфейс). В этом случае, если объект предоставляет интерфейс буферов, доступных для чте- ния, возвращаются указатель на буфер и его размер. Наконец, если при использовании спецификаторов “es#” и “et#” переданы непустой указатель и ненулевая длина, предполагается, что они представляют буфер, уже раз- мещенный в памяти, куда можно сохранить результат преобразования.
    В этом случае интерпретатор не будет выделять память для результата, и вам не потребуется вызывать функцию PyMem_Free().
    Спецификаторы “s*” и “z*” по своему действию напоминают спецификато- ры “s#” и “z#”, но в отличие от последних они заполняют структуру Py_buf-
    _buf- buf- fer информацией о принятых данных. Дополнительные сведения об этом можно найти в документе PEP-3118, а здесь отмечу лишь, что эта струк-
    PEP-3118, а здесь отмечу лишь, что эта струк-
    -3118, а здесь отмечу лишь, что эта струк- тура как минимум имеет атрибуты char *buf, int len и int itemsize, ко- торые определяют адрес буфера в памяти, его размер (в байтах) и размер элементов, хранящихся в буфере. Кроме того, интерпретатор устанавлива- ет блокировку на доступ к буферу, которая предотвращает его изменение другими потоками управления, пока буфер обрабатывается программным кодом расширения. Это позволяет расширению обрабатывать содержимое буфера независимо и даже, возможно, в потоке управления, отличном от того, в котором выполняется интерпретатор. В связи с этим на пользовате- ля возлагается обязанность вызвать функцию PyBuffer_Release() после за- вершения работы с буфером.
    Спецификаторы “t#”, “w”, “w#” и “w*” действуют точно так же, как семейство спецификаторов “s”, за исключением того, что они принимают только объ- екты, реализующие интерфейс буферов. Спецификатор “t#” требует, чтобы буфер был доступен для чтения. Спецификатор “w” требует, чтобы буфер был доступен для чтения и для записи. Объект в языке Python, поддержи-
    Python, поддержи-
    , поддержи- вающий интерфейс буфера, доступного для записи, считается изменяемым объектом. Поэтому для таких объектов считается допустимым изменять их содержимое в расширениях на языке C.
    Спецификаторы “y”, “y#” и “y*” также напоминают семейство специфика- торов “s”, за исключением того, что они принимают только строки байтов.

    Модули расширений
    1   ...   62   63   64   65   66   67   68   69   ...   82


    написать администратору сайта