Загрузка С библиотек

Python может загружать библиотеки на С и вызывать функции из них. Для этого можно воспользоваться модулем стандартной библиотеки ctypes или модулем cffipip.

Модуль ctypes требует явного описания сигнатуры (списка аргументов и возвращаемого значения) вызываемой функции на Python, cffi, же включает синтаксический анализатор C, благодаря которому может разбирать заголовочные файлы .h и получать оттуда информацию о структурах.

Загрузка библиотеки в ctypes

import ctypes

# В *nix разделяемые библиотеки - файлы .so
lib = ctypes.CDLL('./mylib.so')

# В Windows - файлы .dll
lib = ctypes.CDLL('./mylib.dll')

Вызов функции в ctypes

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)

Некоторые популярные типы 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. Подробнее в документации.

Загрузка библиотеки и вызов функции в cffi

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 представление структуры

Что еще нужно знать о вызове С функций

  • Написание критичных с точки зрения производительности участков кода на C — один из стандартных способов разогнать Python.
  • Ошибка в С библиотеке не может быть обработана на уровне Python и приведет к аварийному завершению интерпретатора.
  • Анализатор С pycparser который использует cffi поддерживает не все возможности языка С, а также не умеет обрабатывать директивы препроцессора (#include, #ifdef и т.п.).
  • Для CPython можно писать модули С — CPython Extensions.