Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Embedding Python

Iniciado por deadLock++, 27 de Diciembre de 2002, 12:01:38 AM

« anterior - próximo »

deadLock++

                                Estoy embebiendo Python en un pequeño motor de mi autoría. El motor está realizado en C++ y mi idea es poder extender la funcionalidad del mismo con scripts Python (especialmente lo referido a GUI y IA).

Es importante que los scripts en Python puedan acceder al Object Model de mi Motor para que sea útil. Mapeando funciones no hay problema ya que codeo:

long metodo(long i) { return ++i; };



static PyMethodDef prueba_methods[] = {

{"metodo",    py_prueba_metodo,     1,  ""},

{NULL,      NULL}};



static PyObject * py_prueba_metodo(PyObject *self, PyObject *args)

{

   long i;

   if (!PyArg_ParseTuple(args, "l", &i))

return NULL;

   

    return Py_BuildValue("l", metodo(i));

}



void init_pyextension()

{

   PyImport_AddModule("prueba");

   Py_InitModule("prueba", prueba_methods);

}

 


y listo. El problema viene con las instancias de los diferentes objetos. Como mapear los métodos no estáticos de las clases.

Se me había ocurrido pasar como argumento el nombre del objeto a un método estático y que la clase lleve registro del nombre de los objetos instanciados junto con su referencia en una propiedad también estática, realizando el mapeo al objeto pasado como parámetro. Pero debería existir una solución un poco mas elegante.

¿Alguien ya lidió con este problema?                                

ethernet

Umh, cierto elemento en el cotd de flipcode escribio acerca de eso www.flipcode.com/cotd

Para solucionar ese problema necesitas usar callbacks. Busca en google acerca de ellos y del pattern Functor.

saludos

deadLock++

                                Muchas gracias, tu link me sirvió mucho y me abrió un abanico de documentos.

Finalmente logré realizar la implementación y escribí mi humilde experiencia en un documento que tal le sirva a alguien:

http://www.dedalus-software.com.ar/docs/em...iendopython.pdf

¡Gracias!  :D

deadLock++                                

CoLSoN2

                                muy currado el PDF, aunque estoy más interesado por LUA, pero thx igualmente =)                                
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

ethernet

Deberias mandar un mail a stratos para q lo pongan en la portada :)

No estaria mal q enviaras el codigo de ejemplo como codigo de la semana

saludos

ethernet

Por otra parte mirando el codigo no me gusta mucho la idea de q desde python manejes directamente una posicion de memoria. No soy un experto pero puede plantear problemas de seguridad y hacer petar el programa.

Por ejeplo en python pillas la referencia y pones obj = 0;
despue cuando llames a la funcion


...

if (!PyArg_ParseTuple(args, "lh", &lRefObject, &s))

return NULL;

return Py_BuildValue("h",

((CPrueba *) lRefObject)->SetValor(s));



resulta q dara un segment fault en ((CPrueba *) lRefObject)->SetValor(s));

De todas maneras no encuentro ningun otra forma q no sea cutre de hacer eso.

PD: por q no usas los cast q te ofrece c++ como reinterpret_cast?

saluos

deadLock++

                                El asunto de pasar las referencias es un tema, un modo de evitarlo sería el siguiente:

Cada objeto posee un propiedad nombre, en cada constructor se introduce en una lista estática la referencia al nuevo objeto creado. Se transfiere el nombre del objeto (y no su referencia) a cada script y el script hace lo propio para invocar métodos no estáticos de la clase.

El inconveniente aquí es que con cada llamada el método estático que envuelve a la función a llamar debería buscar en esta lista por nombre y de este modo conseguir la referencia y poder finalmente realizar la llamada. Quise evitar esta indirección por una cuestión de eficacia.

Algo que si podría agregar es un "validate" que verifique en esta lista si existe realmente esta referencia como instancia de la clase antes de realizar una llamada para evitar un segment fault. Este validate sería una función estática más que podría llamar (o no) el script, por lo tanto si estás en una área del juego que no requiera tanta optimización(como el GUI por ejemplo) cada llamada podría validarse antes mas o menos así:

import Prueba



def funcion(ref):

     

     ok = Prueba.validar(ref)

   

     if (ok == 1) :

           Prueba.SetPos(ref, 5, 3)
                               

ethernet

Aja, entiendo el tema del nombre, para solventar un poco el tema de eficacia lo ideal seria una tabla hash, pero obviamnete seria mas lento y usaria mas memoria q el metodo directo.

saludos






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.