سؤال

أريد استخدام المشغلين الجديد والحذف لإنشاء وتدمير كائناتي.

المشكلة هي بيثون يبدو أنها تقطعها إلى عدة مراحل. TP_NEW، TP_INIT و TP_ALLOC لإنشاء و TP_DEL، TP_FREE و TP_DEALLOC للتدمير. ومع ذلك، فإن C ++ لديه جديد جديد يخصص ويقوم بالكامل بالكائن وحذفه الذي يدمر وكائن الكائن.

أي من أساليب Python TP_ * التي أحتاج إلى تقديمها وما يجب عليهم فعلها؟

أيضا أريد أن أكون قادرا على إنشاء الكائن مباشرة في C ++ على سبيل المثال "Pyobject * OBJ = New MyExionObject (Args)؛" هل سأحتاج أيضا إلى التحميل الزائد للمشغل الجديد بطريقة ما لدعم هذا؟

أود أيضا أن أكون قادرا على تصنيف أنواع الإرشاد الخاصة بي في بيثون، هل هناك أي شيء خاص أحتاج إلى القيام به لدعم هذا؟

أنا أستخدم بيثون 3.0.1.

عدل الكثير من الاشياء C ++ الموجودة التي تفترض أن هذا النوع من الأشياء ثابتة). إذا لم أقم بتنفيذها، فهل ستوقف الأشخاص الذين يتوصلون الأشخاص __init__ بعد إنشائها (أو على الأقل تجاهل المكالمة، مثل Tuple يفعل). أو يجب أن يكون لدي بعض العلم الذي يلقي استثناء أو شيء إذا كان TP_INIT يسمى أكثر من مرة واحدة على نفس الكائن؟

بصرف النظر عن ذلك أعتقد أنه حصلت على معظم الباقي مرتبة.

extern "C"
{
    //creation + destruction
    PyObject* global_alloc(PyTypeObject *type, Py_ssize_t items)
    {
        return (PyObject*)new char[type->tp_basicsize + items*type->tp_itemsize];
    }
    void global_free(void *mem)
    {
        delete[] (char*)mem;
    }
}
template<class T> class ExtensionType
{
    PyTypeObject *t;
    ExtensionType()
    {
        t = new PyTypeObject();//not sure on this one, what is the "correct" way to create an empty type object
        memset((void*)t, 0, sizeof(PyTypeObject));
        static PyVarObject init = {PyObject_HEAD_INIT, 0};
        *((PyObject*)t) = init;

        t->tp_basicsize = sizeof(T);
        t->tp_itemsize  = 0;

        t->tp_name = "unknown";

        t->tp_alloc   = (allocfunc) global_alloc;
        t->tp_free    = (freefunc)  global_free;
        t->tp_new     = (newfunc)   T::obj_new;
        t->tp_dealloc = (destructor)T::obj_dealloc;
        ...
    }
    ...bunch of methods for changing stuff...
    PyObject *Finalise()
    {
    ...
    }
};
template <class T> PyObjectExtension : public PyObject
{
...
    extern "C" static PyObject* obj_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
    {
        void *mem = (void*)subtype->tp_alloc(subtype, 0);
        return (PyObject*)new(mem) T(args, kwds)
    }
    extern "C" static void obj_dealloc(PyObject *obj)
    {
        ~T();
        obj->ob_type->tp_free(obj);//most of the time this is global_free(obj)
    }
...
};
class MyObject : PyObjectExtension<MyObject>
{
public:
    static PyObject* InitType()
    {
        ExtensionType<MyObject> extType();
        ...sets other stuff...
        return extType.Finalise();
    }
    ...
};
هل كانت مفيدة؟

المحلول

الوثائق لهذه في http://docs.python.org/3.0/c-api/typeobj.html. وhttp://docs.python.org/3.0/extending/newtypes.html. يصف كيفية جعل النوع الخاص بك.

TP_ALLOC يقوم بتخصيص الذاكرة المنخفضة المستوى للمثيل. هذا يعادل Malloc ()، بالإضافة إلى تهيئة RefcNT إلى 1. Python لديه مخصص الخاص به، pytype_genericalloc، ولكن يمكن للنوع تطبيق مخصص متخصص.

TP_NEW هو نفس python __new__. يستخدم عادة للأشياء غير القابلة للتغيير حيث يتم تخزين البيانات في المثيل نفسه، مقارنة بمؤشر إلى البيانات. على سبيل المثال، تخزين السلاسل والزخات بياناتها في المثال، بدلا من استخدام Char * أو Pytuple *.

بالنسبة لهذه الحالة، TP_NEW أرقام مقدار الذاكرة اللازمة، بناء على معلمات الإدخال، واتصل TP_ALLOC للحصول على الذاكرة، ثم تهيئة الحقول الأساسية. لا يحتاج TP_NEW إلى الاتصال TP_ALLOC. يمكن أن ترجع على سبيل المثال كائن مخزن مؤقتا.

tp_init هو نفس python __init__. يجب أن يكون معظم التهيئة الخاصة بك في هذه الوظيفة.

يسمى التمييز بين __new__ و __init__ التهيئة ذات المرحلة, ، أو تهيئة مرحتين.

قول انت "C ++ فقط لديه جديد"لكن هذا غير صحيح. تتوافق TP_ALLOC مخصصا مخصصا للمكونات المخصصة في C ++، __new__ يتوافق مع مخصص نوع مخصص (وظيفة المصنع)، و __init__ أكثر مثل المنشئ. يناقش هذا الرابط الأخير المزيد عن الموازية بين C ++ و Python Style.

قرأت أيضا http://www.python.org/download/releases/2.2/descrintro/ للحصول على تفاصيل حول كيفية تفاعل __new__ و __init__.

تكتب أنك تريد "إنشاء الكائن مباشرة في C ++". هذا صعب للغاية لأنه على الأقل سيكون عليك تحويل أي استثناءات بيثون التي حدثت أثناء إنشاء مثيل كائن في استثناء C ++. قد تحاول النظر في دفعة :: Python للحصول على بعض المساعدة في هذه المهمة. أو يمكنك استخدام تهيئة مرحلتين. ؛)

نصائح أخرى

لا أعرف آبهة برمجة التطبيقات بيثون على الإطلاق، ولكن إذا كان بيثون يقسم التخصيص والتهيئة، يجب أن تكون قادرا على استخدام التنسيب الجديد.

على سبيل المثال:

 // tp_alloc
 void *buffer = new char[sizeof(MyExtensionObject)];
 // tp_init or tp_new (not sure what the distinction is there)
 new (buffer) MyExtensionObject(args);
 return static_cast<MyExtensionObject*>(buffer);

 ...
 // tp_del
 myExtensionObject->~MyExtensionObject(); // call dtor
 // tp_dealloc (or tp_free? again I don't know the python apis)
 delete [] (static_cast<char*>(static_cast<void*>(myExtensionObject)));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top