Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

binlib [2023/04/10 09:50] (текущий)
root создано
Строка 1: Строка 1:
 +<div slide>
 +
 +====== Загрузка С библиотек ======
 +
 +Python может загружать библиотеки на С и вызывать функции из них. Для этого можно воспользоваться модулем стандартной библиотеки ''ctypes'' или  модулем ''cffi''<sup>pip</sup>.
 +
 +Модуль ''ctypes'' требует явного описания сигнатуры (списка аргументов и возвращаемого значения) вызываемой функции на Python, ''cffi'', же включает синтаксический анализатор C, благодаря которому может разбирать заголовочные файлы ''.h'' и получать оттуда информацию о структурах.
 +
 +===== Загрузка библиотеки в ctypes =====
 +
 +<sxh python>
 +import ctypes
 +
 +# В *nix разделяемые библиотеки - файлы .so
 +lib = ctypes.CDLL('./mylib.so')
 +
 +# В Windows - файлы .dll
 +lib = ctypes.CDLL('./mylib.dll')
 +</sxh>
 +
 +</div><div slide>
 +
 +===== Вызов функции в ctypes =====
 +
 +<sxh python>
 +
 +foo = lib.foo
 +foo.restype = ctypes.c_double
 +foo.argtypes = [ctypes.c_int, ctypes.c_double]
 +
 +# Теперь функцию foo можно вызывать, как обычную функцию Python.
 +
 +ret = foo(5, 3.2)
 +print(ret)
 +</sxh>
 +
 +</div><div slide>
 +
 +==== Некоторые популярные типы ctypes ==== 
 +
 +^ Тип ctypes ^ Тип C ^ Тип Python ^
 +| ''c_byte'' | ''char'' | ''int'' |
 +| ''c_ubyte'' | ''unsigned char'' | ''int'' |
 +| ''c_int'' | ''int'' | ''int'' |
 +| ''c_double'' | ''double'' | ''float'' |
 +| ''c_char_p'' | ''char *'' | ''str'' или ''None'' |
 +| ''c_int * 10'' | ''int [10]'' | ''list(int, ...)'' |
 +
 +Так как строки в Python являются константами, для создания изменяемого массива типа ''c_char_p'' используется метод ''create_string_buffer''. Подробнее в [[https://docs.python.org/3.6/library/ctypes.html|документации]].
 +
 +</div><div slide>
 +
 +===== Загрузка библиотеки и вызов функции в cffi =====
 +
 +<sxh python>
 +import cffi
 +
 +# Создаем объект пространства имен cffi
 +ffi = cffi.FFI()
 +
 +# Загружаем заголовочный файл
 +with open("mylib_header.h") as f:
 +    ffi.cdef(f.read())
 +
 +# Загружаем библиотеку
 +lib = ffi.dlopen("mylib.so")
 +
 +# Вызываем функцию
 +result = lib.foo(5, 3.2)
 +
 +# Создаем объект - структуру данных объявленную в заголовочном файле
 +my_data_struct = self.ffi.new("DataStruct *")
 +
 +my_data_struct.a = 15 # Работаем с полями структуры на Python
 +
 +ffi.buffer(my_data_struct) # Получаем bytes представление структуры
 +
 +</sxh>
 +
 +</div><div slide>
 +
 +===== Что еще нужно знать о вызове С функций =====
 +
 +  * Написание критичных с точки зрения производительности участков кода на C — один из стандартных способов разогнать Python.
 +  * Ошибка в С библиотеке не может быть обработана на уровне Python и приведет к аварийному завершению интерпретатора.
 +  * Анализатор С ''pycparser'' который использует ''cffi'' поддерживает не все возможности языка С, а также не умеет обрабатывать директивы препроцессора (''#include'', ''#ifdef'' и т.п.).
 +  * Для CPython можно писать модули С — [[http://book.pythontips.com/en/latest/python_c_extension.html|CPython Extensions]].
 +
 +</div>
 +
 +
 +