Использование нескольких модулей / типов с Python C API? - PullRequest
3 голосов
/ 26 января 2010

У меня есть два разных модуля расширения Python; давайте назовем их 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;

Однако, согласно интерпретатору Python, я возвращаю класс, для которого я вызвал метод. (т.е. myclassinstance.mymethod () возвращает myclassinstance).

Я, очевидно, поступаю неправильно, но я понятия не имею, что такое правильный путь. Какие-либо предложения? Просто чтобы отрезать кого-либо, кто собирается это предложить - нет, я не заинтересован в использовании SWIG или Boost :: Python. Я уже пробовал это сделать, и базовый класс хранилища для контейнера тоже не очень понравился (SWIG даже не смог разобрать). До сих пор выполнение расширений само по себе было довольно безболезненным, но я в тупике.

1 Ответ

3 голосов
/ 26 января 2010

Ваша проблема в том, что type->tp_init не делает то, что вы хотите. type->tp_init вызывается после того, как объект выделен для создания экземпляра. Сначала вы должны выделить объект, используя type->tp_new, а затем передать этот объект в качестве первого аргумента type->tp_init. Поскольку вы передаете неинициализированный указатель на tp_init, все ставки отключены. Однако обычно вы не вызываете ни одну из функций напрямую, а вместо этого вызываете одну из PyObject_Call*() для самого объекта типа, чтобы создать новый экземпляр. Или предоставьте обычную функцию C для создания нового экземпляра, например, PyFoo_New().

Тем не менее, обычный способ взаимодействия между двумя модулями расширения - это сделать это через Python API. Если вы хотите, чтобы модуль B импортировал и использовал модуль A, вы вызываете PyImport_Import(), чтобы получить объект модуля, PyObject_GetAttrString(), чтобы получить объект типа, который вам нужен, и один из PyObject_Call*(), чтобы создать его экземпляр. В любом месте, где вы хотите хранить указатель на этот тип, вы просто берете PyObject *.

...