باستخدام وحدات/أنواع متعددة مع Python C API؟
-
22-09-2019 - |
سؤال
لقد حصلت على وحدتي تمديد بيثون مختلفة. دعنا نسميهم A و B. الوحدة A يحتوي على نوع فئة تخزين يسمى الحاوية التي أريد استخدامها داخل الوحدة B كنوع إرجاع طريقة الفصل.
لا يمكنني العثور على أي وثائق حول كيف من المفترض أن أفعل ذلك. لقد تابعت هذه المقالة تقريبًا لإنشاء الوحدات/الفئات ، إلا أنني لم أعلن عن كل الطرق الثابتة ، بحيث يمكن الوصول إليها: http://nedbatchelder.com/text/whirlext.html
سؤالي هو إذن ، كيف يمكنني إنشاء مثيل للحاوية التي يمكنني أن أعود إليها كقيمة إرجاع pyobject* لطريقة الفصل في الوحدة B؟ يبدو تعريف الحاوية هكذا:
typedef struct {
PyObject_HEAD
storageclass* cnt_;
} container;
حاولت ببساطة القيام بما يلي في الطريقة المعنية ، حيث تكون Container_init هي الطريقة التي سجلتها كـ TP_INIT لفئة الحاوية:
pycnt::container* retval;
pycnt::container_init(retval, NULL, NULL);
return (PyObject*)retval;
ومع ذلك ، وفقًا لمترجم بيثون ، سأعود إلى الفصل الذي أسميته الطريقة. (أي ، myclassinstance.mymethod () يعيد myclassinstance).
من الواضح أني أسير في هذا الأمر بطريقة خاطئة ، لكن ليس لدي أي فكرة عن الطريقة الصحيحة. أي اقتراحات؟ فقط لقطع أي شخص سيقترح ذلك - لا لست مهتمًا باستخدام Swig أو Boost :: Python. لقد جربت ذلك بالفعل ولم يلعب فئة التخزين الأساسية للحاوية بشكل جيد مع أي منهما (لم يستطع Swig تحليله). حتى الآن ، لم يكن إجراء الامتدادات بنفسي غير مؤلم ، لكنني متعثر على هذا.
المحلول
مشكلتك هي ذلك type->tp_init
لا تفعل ما تريد. type->tp_init
يتم استدعاؤه بعد تخصيص كائن للقيام بهذا مثيل. يجب عليك أولاً تخصيص الكائن باستخدام type->tp_new
, ، ثم تمرير هذا الكائن كوسيطة أولى إلى type->tp_init
. منذ أن تمرير مؤشر غير ضروري إلى tp_init
, ، انتهت الرهانات. عادة لا تتصل أي من الوظائف مباشرة ، وبدلاً من ذلك اتصل بأحد PyObject_Call*()
على كائن النوع نفسه لإنشاء مثيل جديد. أو توفير وظيفة C عادية لإنشاء مثيل جديد ، لوس أنجلوس PyFoo_New()
.
ومع ذلك ، فإن الطريقة المعتادة للقيام بالتواصل بين وحدتين تمديد هي القيام بذلك من خلال API Python. إذا كنت تريد الوحدة B لاستيراد واستخدام الوحدة A ، فأنت تتصل بها PyImport_Import()
للحصول على كائن الوحدة ، PyObject_GetAttrString()
للحصول على كائن النوع الذي تهتم به ، وواحد من PyObject_Call*()
لإنشاء مثيل لها. في أي مكان تريد تخزين مؤشر لهذا النوع ، سوف تأخذ فقط PyObject *
.