سؤال

لقد كنت أحضنا مع العديد من مغلفة Python C ++ مؤخرا، في محاولة للعثور على واحدة تلبي احتياجات كل من المشاريع المهنية والهواية. لقد شربنا في pycxx. كتوازن جيد بين أن تكون خفيفة الوزن وسهلة واجهة مع أثناء إخفاء بعض من أبشع أجزاء من API بيثون ج. PYCXX غير قوي عندما يتعلق الأمر بضغط الأنواع، ومع ذلك (IE: يطلب منك إنشاء مصانع نوع بدلا من تطبيق المنشور)، وكنا يعملون على ملء الفجوات من أجل فضح أنواعنا بطريقة أكثر وظيفية وبعد من أجل ملء هذه الفجوات، ننتقل إلى API C.

ومع ذلك، فقد تركنا هذا مع بعض الأسئلة، أن وثائق API لا تغطي في عمق كبير (وعندما تقوم بذلك، فإن الإجابات متناقضة في بعض الأحيان). السؤال الرئيسي الأساسي هو ببساطة هذا: ما يجب تعريفه لنوع بيثون لتعمل كوعي أساسي؟ لقد وجدنا أنه بالنسبة لفئة PYCXX لتعمل كنوع نحتاج إلى تحديد TP_NEW و TP_DEALLOC بشكل صريح وتعيين الكتابة كسمية كحدولة، وأننا نحتاج إلى تعيين py_tpflags_basetype على [لدينا نوع] -> TP_FLAGS، ولكن بعد أننا ما زلنا نلتزم في الظلام.

هنا هو كودنا حتى الآن:

class kitty : public Py::PythonExtension<kitty> {
public:
    kitty() : Py::PythonExtension<kitty>() {}
    virtual ~kitty() {}

    static void init_type() {
        behaviors().name("kitty");
        add_varargs_method("speak", &kitty::speak);
    }

    static PyObject* tp_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) {
        return static_cast<PyObject*>(new kitty());
    }

    static void tp_dealloc(PyObject *obj) {
        kitty* k = static_cast<kitty*>(obj);
        delete k;
    }

private:
    Py::Object speak(const Py::Tuple &args) {
        cout << "Meow!" << endl;
        return Py::None();
    }
};

// cat Module
class cat_module : public Py::ExtensionModule<cat_module> {
public: 
    cat_module() : Py::ExtensionModule<cat_module>("cat") {

        kitty::init_type();

        // Set up additional properties on the kitty type object
        PyTypeObject* kittyType = kitty::type_object();
        kittyType->tp_new = &kitty::tp_new;
        kittyType->tp_dealloc = &kitty::tp_dealloc;
        kittyType->tp_flags |= Py_TPFLAGS_BASETYPE;

        // Expose the kitty type through the module
        module().setAttr("kitty", Py::Object((PyObject*)kittyType));

        initialize();
    }
    virtual ~cat_module() {}
};

extern "C" void initcat() {
    static cat_module* cat = new cat_module();
}

ويبدو كود اختبار Python الخاص بنا هذا:

import cat

class meanKitty(cat.kitty):
    def scratch(self):
        print "hiss! *scratch*"

myKitty = cat.kitty()
myKitty.speak()

meanKitty = meanKitty()
meanKitty.speak()
meanKitty.scratch()

Bit الغريب هو أنه إذا كنت تعلق على جميع البتات تعاني من تعني، فإن البرنامج النصي يعمل والقط الذي يمتد على ما يرام، ولكن إذا كنت لا تنبثق فئة Meankitty فجأة، فإن Python يعطينا هذا:

AttributeError: 'kitty' object has no attribute 'speak'

الذي يربك حماقة مني. يبدو الأمر كما لو أن الميراث منه يخفي الفئة الأساسية تماما! إذا كان أي شخص يمكن أن يوفر بعض البصيرة في ما نحن في عداد المفقودين، فسيكون موضع تقدير! شكرا!


تحرير: حسنا، حتى حوالي خمس ثوان بعد نشر هذا أتذكر شيئا أرادنا أن نحاول سابقا. أضفت الكود التالي إلى كيتي -

virtual Py::Object getattr( const char *name ) {
    return getattr_methods( name );
}

والآن نحن Meowing على كل من الكتيبات في بيثون! لا تزال غير موجودة بالكامل، لأنني الآن أحصل على هذا:

Traceback (most recent call last):
    File "d:\Development\Junk Projects\PythonCxx\Toji.py", line 12, in <module>
    meanKitty.scratch()
AttributeError: scratch

لذلك لا تزال تبحث عن بعض المساعدة! شكرا!

هل كانت مفيدة؟

المحلول

يجب أن تعلن kitty كما class new_style_class: public Py::PythonClass< new_style_class >. وبعد يرى simple.cxx وحالة اختبار بيثون في http://cxx.svn.sourceforge.net/viewvc/cxx/trunk/cxx/demo/python3/.

قدمت Python 2.2 دروسا جديدة على الطراز الجديد والتي تتيح من بين أشياء أخرى للمستخدم الأنواع المدمجة من الفئة الفرعية (مثل النوع المدمج الجديد). لم ينجح الميراث في مثالك لأنه يحدد فئة نمط قديم.

نصائح أخرى

لقد قمت بسحب جزء صغير من العمل مع PYCXX، وأنا لست في مترجم، لكنني أظن أن ما تراه يشبه الوضع التالي، كما هو معبر عنه في بيثون نقي:

>>> class C(object):
...   def __getattribute__(self, key):
...     print 'C', key
... 
>>> class D(C):
...   def __init__(self):
...     self.foo = 1
... 
>>> D().foo
C foo
>>> 

أفضل تخمين لي هو أن C ++ getattr يجب أن تحقق الطريقة this.ob_type->tp_dict (والذي سيكون بالطبع هو DICT Subclass، إذا this مثال على الفئة الفرعية) والاتصال فقط getattr_methods إذا فشلت في العثور عليها name هناك (انظر وظائف API Pydict_).

أيضا، لا أعتقد أنه يجب أن تحدد tp_dealloc نفسك: لا أرى كيف يتحسن تنفيذك على PYCXX الافتراضي extension_object_deallocator.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top