====== Загрузка С библиотек ======
Python может загружать библиотеки на С и вызывать функции из них. Для этого можно воспользоваться модулем стандартной библиотеки ''ctypes'' или модулем ''cffi''pip.
Модуль ''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''. Подробнее в [[https://docs.python.org/3.6/library/ctypes.html|документации]].
===== Загрузка библиотеки и вызов функции в 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 можно писать модули С — [[http://book.pythontips.com/en/latest/python_c_extension.html|CPython Extensions]].