В последнее время мы с другом встречались с различными упаковщиками Python C++, пытаясь найти тот, который отвечает потребностям как профессиональных, так и хобби. Мы оба оттачивали на PyCxx как хороший баланс между легким и удобным интерфейсом, спрятав некоторые из самых уродливых бит Python C api. Однако PyCxx не очень надежна, когда речь заходит об экспонировании типов (т. Е.: Он инструктирует вас создавать фабрики типов, а не создавать конструкторы), и мы работаем над заполнением пробелов, чтобы выявить наши типы более функциональным образом , Чтобы заполнить эти пробелы, перейдем к C api.Создание наследуемого типа Python с помощью PyCxx
Это оставляет нам некоторые вопросы, однако, что документация api, похоже, не покрывает большую глубину (и когда это происходит, ответы иногда противоречивы). Основной всеобъемлющий вопрос заключается в следующем: что должно быть определено для типа Python для использования в качестве базового типа? Мы обнаружили, что для класса 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()
Любопытно бит, что если вы прокомментировать все meanKitty биты из, сценарий бежит, а кошка мяукает просто отлично, но если вы раскомментируете класс MeanKitty внезапно, Python дает нам это:
AttributeError: 'kitty' object has no attribute 'speak'
Что сбивает меня с ума. Это как если бы наследование от него полностью скрывает базовый класс! Если бы кто-нибудь мог дать некоторое представление о том, чего нам не хватает, это было бы оценено! Благодаря!
EDIT: Хорошо, примерно через пять секунд после публикации этого сообщения я вспомнил то, что мы хотели попробовать раньше. Я добавил следующий код в копилке -
virtual Py::Object getattr(const char *name) {
return getattr_methods(name);
}
И теперь мы мяуканье на обоих кошечек в Python! все еще не полностью там, однако, потому что теперь я получаю это:
Traceback (most recent call last):
File "d:\Development\Junk Projects\PythonCxx\Toji.py", line 12, in <module>
meanKitty.scratch()
AttributeError: scratch
Так что ищите помощь! Благодаря!
Вы работаете на pylibcat ++? – joeforker