في العام الماضي ، كانت هناك حاجة لاستكمال مشروع قديم كتب في C مع وظائف في Python3 . على الرغم من وجود مقالات حول هذا الموضوع ، فقد عانيت في ذلك العام والآن عندما كتبت برامج لهذا المقال. لذلك ، سأقدم أمثلة عن كيفية العمل مع Python3 من C تحت Linux (مع ما استخدمته). سوف أصف كيفية إنشاء فصل واستدعاء أساليبه للوصول إلى المتغيرات. استدعاء الوظائف والحصول على المتغيرات من الوحدة النمطية. وكذلك المشاكل التي واجهتها ولم أستطع فهمها.
حزم
نستخدم API Python القياسي لـ C. حزم بيثون المطلوبة:
- python3
- python3 ديف
- python3 للجميع
- python3 بين جميع ديف
- libpython3 بين جميع ديف
العمل في المترجم
أبسط شيء هو التحميل والعمل في مترجم Python.
للعمل ، يجب عليك توصيل ملف الرأس:
#include <Python.h>
تحميل المترجم:
Py_Initialize();
التالي هو كتلة من العمل مع بيثون ، على سبيل المثال:
PyRun_SimpleString("print('Hello!')");
تفريغ المترجم:
Py_Finalize();
مثال كامل:
#include <Python.h> void main() { // Python Py_Initialize(); // PyRun_SimpleString("print('Hello!')"); // Python Py_Finalize(); }
كيفية تجميع وتشغيل:
gcc simple.c $(python3-config --includes --ldflags) -o simple && ./simple Hello!
ولكن هذا لن ينجح:
gcc $(python3-config --includes --ldflags) simple.c -o simple && ./simple /tmp/ccUkmq57.o: In function `main': simple.c:(.text+0x5): undefined reference to `Py_Initialize' simple.c:(.text+0x16): undefined reference to `PyRun_SimpleStringFlags' simple.c:(.text+0x1b): undefined reference to `Py_Finalize' collect2: error: ld returned 1 exit status
هذا لأن python3-config - يشمل - علامات الفلاش تتوسع في هذا النوع من الأشياء:
-I/usr/include/python3.6m -I/usr/include/python3.6m -L/usr/lib/python3.6/config-3.6m-x86_64-linux-gnu -L/usr/lib -lpython3.6m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions
أنا هنا أعتقد أن ترتيب اتصال رابط -Wl مهم . من يعرف أكثر دقة ، أكتب عن ذلك في التعليقات ، وسأكمل الإجابة.
شرح من MooNDeaR :
كل شيء بسيط للغاية - يتم البحث عن الأحرف في مسار واحد ويتم إلقاء جميع الأحرف غير المستخدمة. إذا قمت بوضع simple.c في النهاية ، فقد تبين أن الرابط سيرى استخدام رمز Py_Initialize () بعد أن ينظر إلى مكتبات python ، وسيتم تجاهل جميع رموزها في هذه اللحظة (لأنه لم يتم استخدامها).
مثال على استدعاء دالة من ملف Python:
simple.c
#include <Python.h> void python() { // Python Py_Initialize(); // // sys PyRun_SimpleString("import sys"); // python PyRun_SimpleString("sys.path.append('./src/python')"); PyRun_SimpleString("import simple"); PyRun_SimpleString("print(simple.get_value(2))"); PyRun_SimpleString("print(simple.get_value(2.0))"); PyRun_SimpleString("print(simple.get_value(\"Hello!\"))"); // Python Py_Finalize(); } void main() { puts("Test simple:"); python(); }
simple.py
ولكن هذه أشياء بسيطة وغير مثيرة للاهتمام ، ونحن لا نحصل على نتيجة لهذه الوظيفة.
العمل مع وظائف ومتغيرات الوحدة
هذا هو اصعب قليلا.
تحميل مترجم Python ووحدة func.py فيه:
PyObject * python_init() {
تحرير موارد مترجم Python:
void python_clear() {
العمل مع المتغيرات ووظائف الوحدة النمطية.
char * python_func_get_str(char *val) { char *ret = NULL;
دعونا نتناول هذا بمزيد من التفصيل.
pVal = PyObject_CallFunction(pObjct, (char *) "(s)", val);
"(s)" تعني أنه يتم تمرير معلمة 1 char * كوسيطة إلى get_value (x) . إذا احتجنا إلى تمرير العديد من الوسيطات إلى الوظيفة ، فستكون هكذا:
pVal = PyObject_CallFunction(pObjct, (char *) "(sss)", val1, val2, val3);
إذا كنت بحاجة لتمرير كثافة العمليات ، فسيتم استخدام الحرف الأول ، ويمكن العثور على جميع أنواع البيانات الممكنة وتسمياتها في وثائق Python.
pVal = PyObject_CallFunction(pObjct, (char *) "(i)", my_int);
func.py:
(تم حل المشكلة )
المشكلة التي واجهتها ولم أستطع فهمها بعد:
int main() { puts("Test func:"); if (!python_init()) { puts("python_init error"); return -1; } puts("Strings:"); printf("\tString: %s\n", python_func_get_str("Hello from Python!")); puts("Attrs:"); printf("\ta: %d\n", python_func_get_val("a")); printf("\tb: %d\n", python_func_get_val("b")); printf("\tc: %d\n", python_func_get_val("c")); python_clear(); return 0; }
إذا كنت أرغب في الحصول على b أو c من func.py ، فقم بما يلي:
Py_Finalize();
أحصل على خطأ تجزئة . لا توجد مشكلة من هذا القبيل مع الحصول على فقط.
عند تلقي متغيرات الفصل ، لا توجد مشاكل أيضًا.
شرح من pwl :
PyObject PyDict_GetItemString (PyObject p، const char * key)
قيمة الإرجاع: إشارة المقترضة. لا شيء يجب القيام به للإشارة إلى المقترضة.
كانت المشكلة أنني كنت أتصل بـ Py_XDECREF () من أجل PyDict_GetItemString () . ليس من الضروري القيام بذلك لهذه الوظيفة ، مما يؤدي إلى خطأ تجزئة .
العمل الطبقي
لا يزال هناك أكثر تعقيدا قليلا.
قم بتحميل مترجم Python و class.py في ذلك.
PyObject * python_init() {
تمرير سلسلة كوسيطة واستعادة السلسلة مرة أخرى
char * python_class_get_str(char *val) { char *ret = NULL; pVal = PyObject_CallMethod(pInstance, (char *) "get_value", (char *) "(s)", val); if (pVal != NULL) { PyObject* pResultRepr = PyObject_Repr(pVal);
لم تكن هناك مشاكل هنا ، كل شيء يعمل دون أخطاء. هناك أمثلة في المصدر حول كيفية التعامل مع int ، مزدوج ، منطقي .
أثناء كتابة المواد قمت بتحديث معرفتي)
آمل أن يكون مفيدا.
مراجع