справочник по Python. мм isbn 9785932861578 9 785932 861578
Скачать 4.21 Mb.
|
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 “ 740 Глава 26. Расширение и встраивание интерпретатора Python NotImplementedError: distance() not implemented. (Перевод: Трассировочная информация (самый последний вызов – самый нижний): Файл “ 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”, за исключением того, что они принимают только строки байтов. |