cffi: C 外部関数インターフェース
インライン C 宣言を使い、より Python らしい C 相互運用を cffi で実現します。
「cffi: C 外部関数インターフェース」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。
cffiとは
cffi(C Foreign Function Interface)は、ctypesのクラスではなくCの宣言を使用して、PythonからCコードを呼び出せるようにします。より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)) # 42cdef宣言
Pythonから使用するC関数のシグネチャ、構造体、typedefを宣言するには、ffi.cdef() を使用します。
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) を使用し、Cの文字列ポインターをPythonのbytesに変換するには ffi.string(ptr) を使用します。
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()verifyを使った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)) # 7CからPythonへのコールバック
ffi.callback() を使用して、Cライブラリに渡せるC関数ポインターとしてPython関数をラップします。
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のクラスを使用します。cffiのAPIモードはより高速で、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)) # 5cffiとNumPyの使用
ffi.cast() と配列の ctypes.data ポインターを使用して、cffi経由でNumPy配列のデータを直接Cに渡します。
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関数は通常、戻り値によってエラーを通知します。戻り値を確認し、POSIXのエラーコードには ffi.errno を使用します。
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モードでは、パフォーマンスを向上させるラッパーをコンパイルします。Cのメモリには ffi.new()、PythonからCへのコールバックには ffi.callback() を使用します。
よくある質問
「cffi: C 外部関数インターフェース」レッスンは無料ですか?
はい。「cffi: C 外部関数インターフェース」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。
「cffi: C 外部関数インターフェース」で何を学びますか?
インライン C 宣言を使い、より Python らしい C 相互運用を cffi で実現します。 ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Python Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「cffi: C 外部関数インターフェース」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPython Academyレッスンでコードを書いて実行できますか?
はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- C 拡張の理由: 用途とトレードオフ
- ctypes: Python から C ライブラリを呼び出す
- cffi: C 外部関数インターフェース
- Python C 拡張モジュールの作成