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 والهياكل وtypedefs التي تريد استخدامها من 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 مع verify
يُجمّع وضع 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إدارة الذاكرة
تملك Python الكائنات التي تُخصّص باستخدام ffi.new() وتحررها تلقائيًا. استخدم 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 يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- لماذا امتدادات C؟ حالات الاستخدام والمفاضلات
- ctypes: استدعاء مكتبات C من Python
- cffi: واجهة الدوال الأجنبية لـ C
- كتابة وحدة امتداد C لـ Python