Jump to content
  • Advertisement
Sign in to follow this  
JackRabbit

[Python/SWIG] Singleton access from Python etc...

This topic is 4846 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone! First i just want to warn you that this is a rather lengthy post, so please bear with me :) Ok,i've been able to export a Singleton class from my CPP program to python as an extension module. The class is just a test class i wrote to experiment with some things i want to do with my game. The class just has a static pointer to a CObject ( which a simple test class with just X and Y members ). The singleton is called CObjectManager which will be responsible for creating/destroying objects and things of that sort. Here is the code for this class: ( And yes, i know this isnt a "real" singleton, but that isnt the point ;) )
#ifndef __COBJECTMANAGER_H_INCLUDED__
#define __COBJECTMANAGER_H_INCLUDED__

#include "CObject.h"

extern int gMyInt;

class CObjectManager
{
private:
    static CObject* m_pActiveObject;

    CObjectManager() { }
    ~CObjectManager() { }
    
public:

    static CObject* FetchActiveObject();
    static void SetActiveObject(CObject* objPtr);
};

#endif __COBJECTMANAGER_H_INCLUDED__

Now then, the CPP program will be responsible for this class for initialization and all of that, and the Python script should be able to access this class and use the FetchActiveObject() method to get the object stored. So the CPP program will create a CObject and store it in CObjectManager so that the Python script can get it and do things with it. Follow me so far ? Ok, all of the above works just fine for me, the python script can access CObjectManager and access the methods, HOWEVER , when python calls the method FetchActiveObject() it gets the value None! And ofcourse, since the extension module exposed to python is in a dll library, that is what i would expect, since the CObjectManager that python loads in the DLL wont have any value for its pointer to the stored CObject, since it has its own "instance" for that class. So my question is this: How can i share the CObject pointer that the CPP program creates with Python ? I understand if the above seems confusing to the reader of this post, but just let me know what im missing or is unclear about. NOTE: In the code listing above you might notice the extern int gMyInt; variable, i just put that in there to see if i could set that value in CPP, and if it had the same value in Python, but ofcourse it didnt, as i should have known ;) There, i hope you got enough information to help me on this ( and that its readable ;) ) Thanks for your time! PS: I should note that something i wanted to do before i even begain with exporting modules to Python, i wanted to create my CObject in the CPP program, and pass it as an argument to a function in python using this:
// ... Assumes that pArgs tuple have be set with values
PyObject_CallObject( pFunc,  pArgs );
However i couldnt find anyway to add a custom object to the argument list, using regular datatypes like int and such was easy with the python functions PyInt_FromLong() etc, but since all python functions like this use the PyObject, i relized that i had to somehow cast or convert my CObject into a PyObject, but i have no idea how to do that, and ive looked through all docs i could find but without any results, so if anyone knows how that should be done please let me know :)

Share this post


Link to post
Share on other sites
Advertisement
Anyone... ?

Ok, i guess that my question perhaps is to broad or unclear, which
i wont contest in anyway. Let me ask a simpler question then:

How can i pass an object of my own classes, as an argument to a function
in Python ?

That is, how would i go about converting my own CObject to a PyObject ?

Im asking this since most of the Python/C API functions operate on PyObjects.

Any ideas for how i could do this ?

Thanks!

Share this post


Link to post
Share on other sites
Quote:
Original post by JackRabbit
How can i pass an object of my own classes, as an argument to a function
in Python ?


You need to tell python about that new type. If CObject is not a POD type, you'll have to create a proxy type that stores and manages a CObject* instead of integrating the PyObject header to the CObject itself.

boost::python may help - a lot.

Share this post


Link to post
Share on other sites
Thanks for your reply SiCrane!

I did as you said and it works great :)

However, i now found myself with a different problem, i used the example code
from the documentation
which works fine when i put that code into my main.cpp file.

But when i try to separate the declartion of the type structures into a header
file, and the functions ( just the init function right now ) into a seperate
source file it crashes on me. Runtime python error i get is this:

Exception exceptions.AttributeError: "'noddy.Noddy' object has no attribute 'num
ber'" in 'garbage collection' ignored
Fatal Python error: unexpected exception during garbage collection

Here is the source files:

NOTE:
Although the files are named after the class i want to import to Python,
currently i just use the Noddy example type object from the docs for
simplicity. That object just has one int member called Number.

main.cpp

#include <cstdlib>
#include <iostream>
#include <python.h>

#include "CObject_Py_Wrap.h"

using namespace std;

int main(int argc, char *argv[])
{
PyObject *pScriptFile, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;

Py_Initialize();

/* Here we initialize our Noddy object type and makes it
available to Python so Python knows about it and how to use it. */

initnoddy();

/* Load the python script */
pScriptFile = PyString_FromString("testscript");
pModule = PyImport_Import( pScriptFile );
Py_DECREF( pScriptFile );
if( pModule != NULL )
{
/* Get the modules dictionary so we get get the function
in the script we wish to call */

pDict = PyModule_GetDict( pModule );
pFunc = PyDict_GetItemString(pDict, "MyFunc");
if( pFunc && PyCallable_Check(pFunc) )
{ /* Function check ok */

/* Now create a noddy object. */
noddy_NoddyObject* myNoddy = new noddy_NoddyObject;
myNoddy->number = 34; /* Give the member a value */

/* Initialize the noddy object for Python */
PyObject_INIT(myNoddy,&noddy_NoddyType);

/* Create a PyObject value from the Noddy object
so we can pass it as an argument to our function */

PyObject* pValue = (PyObject *)myNoddy;
Py_INCREF(pValue);
PyObject* pArgs = Py_BuildValue("(O)",pValue);

PyObject_CallObject( pFunc, pArgs );

Py_DECREF(pValue);
Py_DECREF(pArgs);
}
else
{
cout << "Error calling function!.\n";
}
Py_DECREF( pModule );
}
else
{
cout << "FAILED to load script file\n";
}

Py_Finalize();

system("PAUSE");
return EXIT_SUCCESS;
}





CObject_Py_Wrap.h Holds the structures for the Type objects

#ifndef __COBJECT_PY_WRAP_H_INCLUDED__
#define __COBJECT_PY_WRAP_H_INCLUDED__

#include <python.h>
#include "structmember.h"

typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
int number;
} noddy_NoddyObject;

static PyMemberDef Noddy_members[] = {
{"number", T_INT, offsetof(noddy_NoddyObject, number), 0,
"noddy number"},
{NULL} /* Sentinel */
};

static PyTypeObject noddy_NoddyType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"noddy.Noddy", /*tp_name*/
sizeof(noddy_NoddyObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"Noddy objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
Noddy_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};


static PyMethodDef noddy_methods[] = {
{NULL} /* Sentinel */
};

#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initnoddy(void);

#endif /* __COBJECT_PY_WRAP_H_INCLUDED__ */





CObject_Py_Wrap.cpp Holds the implementation of the initnoddy() function

#include "CObject_Py_Wrap.h"


#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initnoddy(void)
{
PyObject* m;

noddy_NoddyType.tp_new = PyType_GenericNew;
if (PyType_Ready(&noddy_NoddyType) < 0)
return;

m = Py_InitModule3("noddy", noddy_methods,
"Example module that creates an extension type.");

Py_INCREF(&noddy_NoddyType);
PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType);
}





Finally here is the Python script:

from time import time,ctime
from noddy import *

def MyFunc(o):
print 'Today is ', ctime(time())
print o.number




It all compiles just fine, but i cant find out why it crashes on me since the
code is exactly the same as before when i had all the Noddy stuff in the main
source file, so i must have missed something when i seperated it into its own
header and source file, but i cant put my finger on what exactly is wrong.

Any ideas ?

NOTE:
I should note that im using Dev-Cpp with the GCC complier for this if that
makes any difference

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!