Путаница в расширениях C ++ Python. Такие вещи, как получение значений C ++ для значений Python - PullRequest
1 голос
/ 01 мая 2010

Я хотел бы преобразовать часть своего кода на Python в C ++ для скорости, но это не так просто, как просто сделать функцию C ++ и сделать несколько вызовов функций. Я понятия не имею, как получить целое число C ++ из целочисленного объекта Python. У меня есть целое число, которое является атрибутом объекта, который я хочу использовать. У меня также есть целые числа, которые находятся внутри списка в объекте, который мне нужно использовать.

Я хотел протестировать создание расширения C ++ с помощью этой функции:

def setup_framebuffer(surface,flip=False):
   #Create texture if not done already
   if surface.texture is None:
      create_texture(surface)
   #Render child to parent
   if surface.frame_buffer is None:
      surface.frame_buffer = glGenFramebuffersEXT(1)
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, c_uint(int(surface.frame_buffer)))
   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, surface.texture, 0)
   glPushAttrib(GL_VIEWPORT_BIT)
   glViewport(0,0,surface._scale[0],surface._scale[1])
   glMatrixMode(GL_PROJECTION)
   glLoadIdentity() #Load the projection matrix
   if flip:
      gluOrtho2D(0,surface._scale[0],surface._scale[1],0)
   else:
      gluOrtho2D(0,surface._scale[0],0,surface._scale[1])

Эта функция вызывает create_texture, поэтому мне придется передать эту функцию в функцию C ++, что я и сделаю с третьим аргументом. Это то, что я имею до сих пор, пытаясь следить за информацией в документации по питону:

#include <Python.h>
#include <GL/gl.h>
static PyMethodDef SpamMethods[] = {
   ...
   {"setup_framebuffer",  setup_framebuffer, METH_VARARGS,"Loads a texture from a Surface object to the OpenGL framebuffer."},
   ...
   {NULL, NULL, 0, NULL}        /* Sentinel */
};
static PyObject * setup_framebuffer(PyObject *self, PyObject *args){
   bool flip;
   PyObject *create_texture, *arg_list,*pyflip,*frame_buffer_id;
   if (!PyArg_ParseTuple(args, "OOO", &surface,&pyflip,&create_texture)){
      return NULL;
   }
   if (PyObject_IsTrue(pyflip) == 1){
      flip = true;
   }else{
      flip = false;
   }
   Py_XINCREF(create_texture);
   //Create texture if not done already
   if(texture == NULL){
      arglist = Py_BuildValue("(O)", surface)
      result = PyEval_CallObject(create_texture, arglist);
      Py_DECREF(arglist);
      if (result == NULL){
         return NULL;
      }
      Py_DECREF(result);
   }
   Py_XDECREF(create_texture);
   //Render child to parent
   frame_buffer_id = PyObject_GetAttr(surface, Py_BuildValue("s","frame_buffer"))
   if(surface.frame_buffer == NULL){
      glGenFramebuffersEXT(1,frame_buffer_id);
   }
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, surface.frame_buffer));
   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, surface.texture, 0);
   glPushAttrib(GL_VIEWPORT_BIT);
   glViewport(0,0,surface._scale[0],surface._scale[1]);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity(); //Load the projection matrix
   if (flip){
      gluOrtho2D(0,surface._scale[0],surface._scale[1],0);
   }else{
      gluOrtho2D(0,surface._scale[0],0,surface._scale[1]);
   }
   Py_INCREF(Py_None);
   return Py_None;
}
PyMODINIT_FUNC initcscalelib(void){
   PyObject *module;
   module = Py_InitModule("cscalelib", Methods);
   if (m == NULL){
      return;
   }
}
int main(int argc, char *argv[]){
   /* Pass argv[0] to the Python interpreter */
   Py_SetProgramName(argv[0]);
   /* Initialize the Python interpreter.  Required. */
   Py_Initialize();
   /* Add a static module */
   initscalelib();
}

Ответы [ 2 ]

2 голосов
/ 01 мая 2010

Могу ли я сделать искреннее предложение здесь? Вместо того, чтобы бросать на себя сотню строк кода при попытке сделать что-то новое, сначала попробуйте самый простой тестовый пример. Попробуйте заставить работать расширение C ++, которое ничего не делает, кроме как возвращает значение 123. (Выбор 0 или 1 может работать случайно, поэтому я выбрал легко распознаваемое значение, которое вряд ли будет случайным.) Затем удвоим расширение номер, который вы передаете, затем добавьте два числа и т. д.

Подкрасться к проблеме! : -)

1 голос
/ 01 мая 2010

Способ получить C int из целого числа Python - с помощью PyInt_AsLong() и понижением (хотя вы можете использовать вместо C длинную.) Чтобы пойти другим путем, вы вызываете PyInt_FromLong(). Для меня не очевидно, где в коде вы хотите это сделать, хотя у меня есть пара других комментариев по поводу вашего кода:

  • Концептуально, PyObject_IsTrue() возвращает логическое значение. Не сравнивайте его с 1, просто используйте его как логическое значение. Тем не менее, вы должны проверить, не вернулась ли ошибка, которая будет равна -1. (Обычная проверка - < 0.) Если вы не проверяете ошибки, вы в конечном итоге проглатываете исключение, но оставляете объект исключения висящим вокруг. Это плохо.

  • Py_XINCREF() из create_texture не является необходимым. У вас есть заимствованная ссылка на кортеж args, который, в свою очередь, владеет ссылкой на объект create_texture. У create_texture нет возможности уйти до того, как ваша функция вернется. Вам нужно только увеличить его, если вы собираетесь хранить его дольше, чем этот вызов функции. Если вам нужно увеличить его, вам не нужно будет использовать Py_XINCREF(), потому что он никогда не будет иметь значение NULL. И если вам действительно нужно было увеличить его, вам также нужно помнить, чтобы оно также расшифровывалось в вашем случае возврата ошибки.

  • Вместо создания кортежа аргумента просто для вызова PyEval_CallObject(), просто вызовите PyObject_CallFunctionObjectArgs(create_texture, arglist, NULL) или PyObject_CallFunction(create_texture, "O", arglist).

  • Py_BuildValue("s", "frame_buffer") не совсем правильный способ получить строку Python для "frame_buffer". Лучший способ - PyString_FromString(). Тем не менее, оба из них возвращают новые ссылки, а PyObject_GetAttr() не использует ссылку на имя атрибута, так что в итоге вы теряете эту ссылку. Вы не должны использовать ни один из них, а вместо этого использовать PyObject_GetAttrString(), который принимает имя атрибута как const char*.

  • Не забудьте проверить возвращаемое значение всех функций, которые могут возвращать значение ошибки (это почти все функции Python API.) Кроме PyTrue_IsTrue() вы также забываете об этом для Py_BuildValue() и PyObject_GetAttr().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...