Главная страница

справочник по 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
страница69 из 82
1   ...   65   66   67   68   69   70   71   72   ...   82
import ctypes
>>> libc = ctypes.CDLL(“/usr/lib/libc.dylib”)
>>> libc.rand()
16807
>>> libc.atoi(“12345”)
12345
>>>
В этом примере напрямую вызываются функции libc.rand() и libc.atoi(), имеющиеся в загруженной библиотеке на языке C.
Модуль ctypes предполагает, что все функции принимают аргумент типа int или char * и возвращают результат типа int. Поэтому, несмотря на то, что предыдущие вызовы были выполнены вполне успешно, вызовы других библиотечных функций на языке C могут работать не так, как ожидается.
Например:
>>> libc.atof(“34.5”)
-1073746168
>>>
Чтобы устранить эту проблему, можно изменить параметры сигнатуры и особенности вызова любой внешней функции func с помощью следующих атрибутов:
func.argtypes
Кортеж типов данных, определенных в модуле ctypes (рассказывается ниже) и описывающих входные аргументы функции func.
func.restype
Тип данных, определенный в модуле ctypes, описывающий возвращаемое значение функции func. Для функций, возвращающих результат типа void, используется значение None.

Модуль ctypes
761
func.errcheck
Вызываемый объект языка Python, принимающий три аргумента (result,
func
, args), где result – это значение, возвращаемое внешней функцией,
func
– ссылка на внешнюю функцию и args – кортеж входных аргументов.
Эта функция вызывается после вызова внешней функции и может исполь- зоваться для проверки наличия ошибок и выполнения других действий.
Ниже приводится пример исправления ошибки в вызове функции atof(), показанной в предыдущем примере:
>>> libc.atof.restype=ctypes.c_double
>>> libc.atof(“34.5”)
34.5
>>>
ctypes.d_double
– это ссылка на предопределенный тип данных. Этот и дру- гие типы данных описываются в следующем разделе.
Типы данных
В табл. 26.5 перечислены типы данных, объявленные в модуле ctypes, кото- рые могут использоваться в качестве значений атрибутов argtypes и restype внешних функций. Колонка «Значение в языке Python» описывает тип данных языка Python, который соответствует указанному типу данных.
Таблица 26.5. Типы данных в модуле ctypes
Имя типа в модуле
ctypes
Тип данных в языке C
Значение в языке Python
c_bool bool
True или False c_bytes signed char
Короткое целое число c_char char
Одиночный символ c_char_p char *
Строка или строка байтов, завер- шающаяся символом NULL
c_double double
Число с плавающей точкой c_longdouble long double
Число с плавающей точкой c_float float
Число с плавающей точкой c_int int
Целое число c_int8
signed char
8-битное целое число c_int16
short
16-битное целое число c_int32
int
32-битное целое число c_int64
long long
64-битное целое число c_long long
Целое число c_longlong long long
Целое число c_short short
Целое число

762
Глава 26. Расширение и встраивание интерпретатора Python
Имя типа в модуле
ctypes
Тип данных в языке C
Значение в языке Python
c_size_t size_t
Це лое число c_ubyte unsigned char
Целое число без знака c_uint unsigned int
Целое число без знака c_uint8
unsigned char
8-битное целое число без знака c_uint16
unsigned short
16-битное целое число без знака c_uint32
unsigned int
32-битное целое число без знака c_uint64
unsigned long long
64-битное целое число без знака c_ulong unsigned long
Целое число без знака c_ulonglong unsigned long long
Целое число без знака c_ushort unsigned short
Целое число без знака c_void_p void *
Целое число c_wchar wchar_t
Одиночный символ Юникода c_wchar_p wchar_t *
Строка Юникода, завершающая- ся символом NULL
Чтобы создать тип, представляющий указатель языка C, к одному из пере-
C, к одному из пере-
, к одному из пере- численных типов данных следует применить следующую функцию:
POINTER(type)
Определяет тип, который является указателем на значение типа type. На- пример, вызов POINTER(c_int) представляет тип данных языка C int *.
Чтобы определить тип, представляющий массив фиксированного размера, достаточно умножить существующий тип на количество элементов в мас- сиве. Например, выражение c_int*4 представляет тип данных int[4] в язы- ке C.
Чтобы определить тип данных, представляющий структуру или объедине- ние в языке C, необходимо создать класс, производный от одного из базо-
C, необходимо создать класс, производный от одного из базо-
, необходимо создать класс, производный от одного из базо- вых классов Structure или Union. Внутри определения производного класса необходимо объявить атрибут класса _fields_, описывающий его содержи- мое. _fields_ – это список кортежей из 2 или 3 элементов вида (name, ctype) или (name, ctype, width), где поле name – это идентификатор поля структуры,
ctype
– класс, описывающий тип поля, и width – целое число, определяющее ширину битового поля. Например, взгляните на следующую структуру на языке C:
struct Point {
double x, y;
};
Описание этой структуры в терминах модуля ctypes имеет следующий вид:
Таблица 26.5 (продолжение)

Модуль ctypes
763
class Point(Structure):
_fields_ = [ (“x”, c_double),
(“y”, c_double) ]
Вызов внешних функций
Чтобы вызвать функцию из библиотеки, достаточно просто обратиться к соответствующему методу с набором аргументов, типы которых совме- стимы с сигнатурой. Для простых типов данных, таких как c_int, c_double и других, можно просто передавать значения соответствующих им типов в языке Python (целые числа, числа с плавающей точкой и другие). Допу-
Python (целые числа, числа с плавающей точкой и другие). Допу-
(целые числа, числа с плавающей точкой и другие). Допу- скается также передавать экземпляры типов c_int, c_double и подобных им.
В случае массивов допускается передавать последовательности языка Py-
Py- thon совместимых типов.
Чтобы передать внешней функции указатель, необходимо сначала создать экземпляр типа, представляющий значение, на которое будет ссылаться указатель, а затем создать объект указателя с помощью одной из следую- щих функций:
byref(cvalue [, offset])
Представляет легковесный указатель на значение cvalue. Аргумент cvalue должен быть экземпляром типа данных, определяемого модулем ctypes.
Аргумент offset определяет смещение в байтах, которое следует прибавить к значению указателя. Значение, возвращаемое этой функцией, можно ис- пользовать только в вызовах внешних функций.
pointer(cvalue)
Создает экземпляр указателя, ссылающегося на значение cvalue. Аргумент
cvalue
должен быть экземпляром типа данных, определяемого модулем ctypes
. Эта функция создает экземпляр типа POINTER, описанного выше.
Ниже приводится пример, демонстрирующий, как функции на языке C можно передать аргумент типа double *:
dval = c_double(0.0) # Создать экземпляр типа double r = foo(byref(dval)) # Вызвать foo(&dval)
ёёё
p_dval = pointer(dval) # Создать переменную-указатель r = foo(p_dval) # Вызвать foo(p_dval)
ёёё
# Проверить значение dval после вызова функции print (dval.value)
Следует отметить, что нет никакой возможности создать указатель на зна- чение встроенного типа, такого как int или float. Передача указателей на значения таких типов противоречила бы принципу неизменяемости, если внутри функции на языке C выполнялась бы попытка изменить значение.
Атрибут cobj.value экземпляра типа cobj, созданного средствами модуля ctypes
, содержит само значение. Например, в предыдущем фрагменте при обращении к атрибуту dval.value возвращается значение с плавающей точ- кой, хранящееся в экземпляре dval класса c_double.

764
Глава 26. Расширение и встраивание интерпретатора Python
Чтобы передать функции на языке C структуру, следует создать экземпляр структуры или объединения. Для этого требуется вызвать конструктор ра- нее объявленного класса структуры или объединения StructureType:
StructureType(*args, **kwargs)
Создает экземпляр StructureType, где под StructureType подразумевается класс, производный от класса Structure или Union. Позиционные аргументы в *args используются для инициализации полей структуры; они должны следовать в том же порядке, в каком они перечислены в атрибуте _fields_.
Именованные аргументы в **kwargs используются для инициализации только именованных полей структуры.
Альтернативные методы конструирования типов
Все экземпляры типов данных модуля ctypes, такие как c_int, POINTER и другие, обладают методами класса, которые могут использоваться для создания экземпляров типов данных ctypes из других объектов, размещае- мых в памяти.
ty.from_buffer(source [,offset])
Создает экземпляр типа ty, использующий тот же буфер в памяти, что и объект source. Аргумент source должен быть объектом любого типа, кото- рый поддерживает интерфейс буферов, доступных для записи (например, bytearray
, массив объектов array, определяемый модулем array, mmap и так далее). Аргумент offset определяет смещение используемой области в бай- тах относительно начала буфера.
ty.from_buffer_copy(source [, offset])
То же, что и ty.from_buffer(), за исключением того, что создает копию буфе- ра, благодаря чему объект source может быть доступен только для чтения.
ty.from_address(address)
Создает экземпляр типа ty, извлекая значение из области памяти с адресом
address
, который определяется, как целое число.
ty.from_param(obj)
Создает экземпляр типа ty из объекта obj на языке Python. Этот метод мо-
Python. Этот метод мо-
. Этот метод мо- жет принимать только объекты obj, которые могут быть приведены к соот- ветствующему типу. Например, целое число в языке Python может быть преобразовано в экземпляр типа c_int.
ty.in_dll(library, name)
Создает экземпляр типа ty из переменной в разделяемой библиотеке. В ар- ар- ар- гументе library передается экземпляр загруженной библиотеки, например объект, созданный конструктором класса CDLL. В аргументе name передается имя переменной. Этот метод можно использовать для создания оберток во- переменной. Этот метод можно использовать для создания оберток во- переменной. Этот метод можно использовать для создания оберток во-
. Этот метод можно использовать для создания оберток во-
Этот метод можно использовать для создания оберток во- круг глобальных переменных, объявленных в библиотеке.
Следующий пример демонстрирует, как можно создать ссылку на глобаль- ную переменную int status, объявленную в библиотеке libexample.so.

Модуль ctypes
765
libexample = ctypes.CDLL(“libexample.so”)
status = ctypes.c_int.in_dll(libexample,”status”)
Вспомогательные функции
Н
иже перечислены вспомогательные функции, объявленные в модуле ctypes
:
addressof(cobj)
Возвращает адрес объекта cobj в памяти в виде целого числа. Аргумент cobj должен быть экземпляром типа из модуля ctypes.
alignment(ctype_or_obj)
Возвращает целочисленную величину выравнивания для типа, объявлен- ного в модуле ctypes, или объекта. В аргументе ctype_or_obj передается один из типов модуля ctypes или экземпляр такого типа.
cast(cobj, ctype)
Приводит объект cobj типа, объявленного в модуле ctypes, к новому типу
ctype
. Этот метод работает только с указателями, поэтому аргумент cobj должен быть указателем или массивом, а аргумент ctype должен быть ти- пом указателя.
create_string_buffer(init [, size])
Создает символьный буфер, доступный для записи, в виде массива элемен- тов типа c_char. В аргументе init может передаваться целое число, опреде- ляющее размер буфера, или строка, определяющая начальное содержимое буфера. size – это необязательный аргумент, который определяет размер буфера, когда в аргументе init передается строка. По умолчанию аргумент
size
получает значение на единицу больше, чем количество символов в init.
Строки Юникода преобразуются в строки байтов с использованием коди- ровки по умолчанию.
create_unicode_buffer(init [, size])
То же, что и create_string_buffer(), за исключением того, что создает массив элементов типа c_wchar.
get_errno()
Возвращает текущее значение частной, для модуля ctypes, копии перемен- ной errno.
get_last_error()
Возвращает текущее значение частной, для модуля ctypes, копии перемен- ной LastError в Windows.
memmove(dst, src, count)
Копирует count байтов из src в dst. В аргументах src и dst допускается пере- давать целые числа, представляющие адреса значений в памяти или эк- земпляры типов, объявленных в модуле ctypes, которые можно преобразо- вать в указатели. Действует точно так же, как и функция memmove() в стан- дартной библиотеке языка C.

766
Глава 26. Расширение и встраивание интерпретатора Python
memset(dst, c, count)
Записывает count байтов со значением c в область памяти, начиная с адреса
dst
. В аргументе dst допускается передавать целые числа или экземпляры типов, объявленных в модуле ctypes. В аргументе c передается целое число в диапазоне 0-255, представляющее значение байта.
resize(cobj, size)
Изменяет размер внутренней памяти, используемой для представления объекта cobj одного из типов модуля ctypes. Аргумент size определяет но- определяет но- но- но- вый размер в байтах.
set_conversion_mode(encoding, errors)
Определяет кодировку, которая будет использоваться при преобразовании строк Юникода в строки 8-битовых символов. Аргумент encoding определя- ет название кодировки, такое как ‘utf-8’, а аргумент errors – политику об- работки ошибок кодирования, например: ‘strict’ или ‘ignore’. Возвращает кортеж (encoding, errors) с предыдущими значениями настроек.
set_errno(value)
Записывает значение в частную, для модуля ctypes, копию системной пере- менной errno. Возвращает предыдущее значение.
set_last_error(value)
Записывает значение в частную, для модуля ctypes, копию переменной Las- tError в системе Windows и возвращает предыдущее значение.
sizeof(type_or_cobj)
Возвращает размер типа, объявленного в модуле ctypes, или объекта в бай- тах.
string_at(address [, size])
Возвращает строку байтов, представляющую size байтов в памяти, начи- ная с адреса address. Если аргумент size опущен, предполагается, что стро- ка байтов заканчивается символом NULL.
wstring_at(address [, size])
Возвращает строку Юникода, представляющую size многобайтовых сим- волов, начиная с адреса address. Если аргумент size опущен, предполагает- ся, что строка байтов заканчивается символом NULL.
Пример
Следующий пример иллюстрирует применение модуля ctypes для построе- ния интерфейса к набору функций на языке C, использовавшихся в самой первой части этой главы, где описывались особенности создания модулей расширений Python вручную.
# example.py
ёёё
import ctypes
_example = ctypes.CDLL(“./libexample.so”)
ёёё

Модуль ctypes
767
# int gcd(int, int)
gcd = _example.gcd gcd.argtypes = (ctypes.c_int,
ctypes.c_int)
gcd.restype = ctypes.c_int
ёёё
# int replace(char *s, char olcdh, char newch)
_example.replace.argtypes = (ctypes.c_char_p,
ctypes.c_char,
ctypes.c_char)
_example.replace.restype = ctypes.c_int
ёёё
def replace(s, oldch, newch):
sbuffer = ctypes.create_string_buffer(s)
nrep = _example.replace(sbuffer,oldch,newch)
return (nrep,sbuffer.value)
ёёё
# double distance(Point *p1, Point *p2)
class Point(ctypes.Structure):
_fields_ = [ (“x”, ctypes.c_double),
(“y”, ctypes.c_double) ]
ёёё
_example.distance.argtypes = (ctypes.POINTER(Point),
ctypes.POINTER(Point))
_example.distance.restype = ctypes.c_double
ёёё
def distance(a,b):
p1 = Point(*a)
p2 = Point(*b)
return _example.distance(byref(p1),byref(p2))
В общем случае использование модуля ctypes всегда связано с созданием промежуточного уровня на языке той или иной сложности. Например, не- которые функции на языке C могут вызываться непосредственно. Однако иногда может потребоваться реализовать промежуточный уровень, чтобы учесть некоторые особенности программного кода на языке C. Так, как было показано в этом примере, чтобы вызвать функцию replace(), необ- ходимо выполнить дополнительные действия, чтобы учесть тот факт, что функция из библиотеки на языке C изменяет содержимое входного буфера.
Для вызова функции distance() потребовалось выполнить дополнительные операции, чтобы создать из кортежей экземпляры класса Point и передать функции указатели на них.
Примечание
Модуль ctypes обладает огромным количеством дополнительных особенностей, которые не рассматривались здесь. Например, модуль позволяет обращаться к са- мым разным библиотекам в системе Windows и обеспечивает поддержку функций обратного вызова, неполных типов и других особенностей. В электронной доку- ментации можно найти массу примеров, благодаря чему она может служить отлич- ной отправной точкой к дальнейшему изучению модуля.

1   ...   65   66   67   68   69   70   71   72   ...   82


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