cffi: интерфейс внешних функций C
Используйте cffi для более удобного взаимодействия Python с C и встроенными объявлениями C.
«cffi: интерфейс внешних функций C» — бесплатный урок Python Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.
Что такое cffi
cffi (интерфейс внешних функций C) позволяет вызывать код C из Python с помощью объявлений C, а не классов ctypes. Этот подход ближе к стилю Python и часто безопаснее.
# pip install cffi
from cffi import FFI
ffi = FFI()
ffi.cdef("double sqrt(double x);")
libm = ffi.dlopen(None) # current process
print(libm.sqrt(2.0)) # 1.4142...Режимы ABI и API
ffi.dlopen() — это режим ABI: он вызывает существующую разделяемую библиотеку во время выполнения. В режиме API компилируется оболочка на C, поэтому работа выполняется быстрее и надёжнее.
from cffi import FFI
ffi = FFI()
# ABI mode (no compile step):
ffi.cdef("int abs(int x);")
libc = ffi.dlopen("libc.so.6") # Linux
print(libc.abs(-42)) # 42Объявления cdef
Используйте ffi.cdef(), чтобы объявить сигнатуры функций C, структуры и определения типов, которые Вы хотите использовать из Python.
from cffi import FFI
ffi = FFI()
ffi.cdef("""
typedef struct {
double x;
double y;
} Point;
double distance(Point a, Point b);
""")
# lib = ffi.dlopen("mylib.so")Создание структур C
Используйте ffi.new(), чтобы выделить структуру C и задать её поля из Python.
from cffi import FFI
ffi = FFI()
ffi.cdef("typedef struct { int x; int y; } Vec2;")
lib = ffi.dlopen(None)
v = ffi.new("Vec2 *")
v.x = 3
v.y = 4
print(v.x, v.y) # 3 4Строки и буферы
Используйте ffi.new("char[]", n) для изменяемых буферов, а ffi.string(ptr) — для преобразования указателя на строку C в байты Python.
from cffi import FFI
ffi = FFI()
buf = ffi.new("char[]", b"hello world")
print(ffi.string(buf)) # b"hello world"
# Mutable buffer for output:
out = ffi.new("char[128]")
# c_func(out, 128) # fill the buffer
# result = ffi.string(out).decode()Режим API с проверкой
В режиме API компилируется небольшой модуль-оболочка на C, что повышает безопасность типов и производительность. Используйте ffi.set_source() и выполняйте сборку без подключения к сети.
from cffi import FFI
ffi = FFI()
ffi.cdef("int add(int a, int b);")
ffi.set_source("_mylib",
"""
int add(int a, int b) { return a + b; }
"""
)
# Build: python build_mylib.py
# from _mylib import ffi, lib
# print(lib.add(3, 4)) # 7Обратные вызовы из C в Python
Используйте ffi.callback(), чтобы обернуть функцию Python в указатель на функцию C, который можно передать библиотеке C.
from cffi import FFI
ffi = FFI()
ffi.cdef("typedef int (*compare_fn)(int, int);")
@ffi.callback("int(int, int)")
def compare(a, b):
return a - b
# pass compare to a C sort functionУправление памятью
Объекты, выделенные с помощью ffi.new(), принадлежат Python и освобождаются автоматически. Используйте ffi.gc(ptr, destructor), чтобы назначить пользовательскую функцию освобождения.
from cffi import FFI
ffi = FFI()
# ptr freed when Python GC collects it:
buf = ffi.new("int[10]")
buf[0] = 42
print(buf[0]) # 42
# Custom destructor:
# ptr = ffi.gc(lib.alloc(), lib.free)cffi и ctypes
cffi использует строки объявлений C, что естественнее для разработчиков на C, а ctypes — классы Python. Режим API cffi работает быстрее, тогда как ctypes не требует компиляции.
# ctypes approach:
import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.abs.restype = ctypes.c_int
libc.abs.argtypes = [ctypes.c_int]
print(libc.abs(-5)) # 5
# cffi approach:
from cffi import FFI; ffi = FFI()
ffi.cdef("int abs(int);")
lib = ffi.dlopen(None)
print(lib.abs(-5)) # 5Использование cffi с NumPy
Передавайте данные массива NumPy напрямую в C через cffi с помощью ffi.cast() и указателя ctypes.data массива.
import numpy as np
from cffi import FFI
ffi = FFI()
arr = np.array([1.0, 2.0, 3.0])
ptr = ffi.cast("double *", arr.ctypes.data)
# Now ptr can be passed to a C function expecting double*Обработка ошибок с cffi
Функции C обычно сообщают об ошибках через возвращаемые значения. Проверяйте возвращаемые значения и используйте ffi.errno для кодов ошибок POSIX.
import errno as errno_mod
from cffi import FFI
ffi = FFI()
ffi.cdef("int open(const char *path, int flags);")
lib = ffi.dlopen(None)
fd = lib.open(b"/nonexistent", 0)
if fd == -1:
err = ffi.errno
raise OSError(err, "open failed")Быстрая проверка
Какой метод использует cffi для объявления сигнатур функций C, которые Вы хотите вызвать?
Итоги
cffi использует ffi.cdef() для объявления сигнатур C и ffi.dlopen() для вызовов библиотек в режиме ABI. В режиме API компилируется оболочка для повышения производительности. Используйте ffi.new() для работы с памятью C и ffi.callback() для обратных вызовов из Python в C.
Часто задаваемые вопросы
Урок «cffi: интерфейс внешних функций C» бесплатный?
Да — полный текст урока «cffi: интерфейс внешних функций C» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.
Чему я научусь в уроке «cffi: интерфейс внешних функций C»?
Используйте cffi для более удобного взаимодействия Python с C и встроенными объявлениями C. Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Python Academy?
Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «cffi: интерфейс внешних функций C»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Python Academy?
Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Зачем нужны расширения C: применение и компромиссы
- ctypes: вызов библиотек C из Python
- cffi: интерфейс внешних функций C
- Написание расширения Python на C