0Pricing
Python Academy · Урок

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 — локальная установка не требуется.

Все уроки этого курса

  1. Зачем нужны расширения C: применение и компромиссы
  2. ctypes: вызов библиотек C из Python
  3. cffi: интерфейс внешних функций C
  4. Написание расширения Python на C
← Назад к Python Academy