Jump to content
• Advertisement

# Making C++ class have python 'member functions'

This topic is 4390 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

See my next post, please. The question has changed, some, but this information may still be helpful. Now, I'm not really looking for actually creating member functions of my C++ class in Python, but I would like to create something similiar. Essentially, I want my C++ class Entity to have some functions like "OnKeyPres()" which then runs a script in Python which modifies the Entity. So, mabye the OnKeyPress script would look something like so:
def Run(self,data):
if(data.key == LEFT):
self.AddForce(-1.0,0.0)
if(data.key == RIGHT):
self.AddForce(1.0,0.0)
if(data.key == UP):
self.AddForce(0.0,1.0)
if(data.key == DOWN):
self.AddForce(0.0,-1.0)


So, I've tried out Boost.Python and cooked up some POS code.
void Script::RunScript(Entity *e, EventData *data)
{
object module(handle<>(borrowed(PyImport_AddModule("__main__"))));
object dictionary = module.attr("__dict__");
try
{
//Get e and data into Python...
dictionary["self"] = new Entity(e);//Must be garbage collectable
dictionary["data"] = data;

//Run the source
PyRun_SimpleString(source.c_str());

PyRun_SimpleString("Run(self,data)");//run.c_str());-+
}
catch (error_already_set)
{
PyErr_Print();
}

Entity* newEntity = extract<Entity*>(dictionary["self"]);
e->SetSelf(newEntity);
}


Basically, Script is a class that reads in a script from a file, then runs it on a given Entity with some data thrown. This doesn't feel right to me. A couple things are bad: 1. I have to new a copy of e so that it can be GCed by Python. 2. PyErr_Print() doesn't seem to do anything since I don't have a Python window up. 3. It doesn't run the script. 4. I can't just modify e directly, I have to make a copy of it, then modify the copy, then modify e to be like teh copy. Basically, it's a mess, and it doesn't even run the script. I have expose the Entity class and init'ed it. I've checked and it does load the script properly, so it's not that. So, my question is, quite simple really, how the heck do I do this? I'm sure I'm messing something up, because I've only ever used Python as a scripting language in very small test cases before. No turoials I have found have covered much about this with Boost.Python. [Edited by - Ezbez on October 8, 2006 8:44:00 AM]

#### Share this post

##### Share on other sites
Advertisement
Let me refine my question some more, since I haven't gotten any replies:

First, I actually have the scripts running now, which is a big improvement. I had forgotten to insert newlines into the file, heh. Python kinda needed those.

With that out of the way, I still have some problems. I still don't like how I have to make a copy of Entity twice for this to work. It's messy, and simply doesn't work so great. Is there any way to give Python a non-Garbage Collected reference to my Entity? Basically, I want to be able to directly change a C++ variable from within Python. Is that even possible?

#### Share this post

##### Share on other sites
Quote:
 Original post by EzbezLet me refine my question some more, since I haven't gotten any replies:First, I actually have the scripts running now, which is a big improvement. I had forgotten to insert newlines into the file, heh. Python kinda needed those.With that out of the way, I still have some problems. I still don't like how I have to make a copy of Entity twice for this to work. It's messy, and simply doesn't work so great. Is there any way to give Python a non-Garbage Collected reference to my Entity? Basically, I want to be able to directly change a C++ variable from within Python. Is that even possible?

It's definitely possible; Boost.Python is just really poorly documented. :)

Instead of using PyRun_SimpleString(), what you want to do is call your function using boost::python::call<>(), which allows you to pass in an arbitrary number of arguments and even get a return value back from the function. Here is some sample code:

void Script::RunScript(Entity *e, EventData *data){     try     {          PyObject* moduleName = PyString_FromString("OnKeyPress");          PyObject* onKeyPressModule = PyImport_Import(moduleName);          Py_DECREF(moduleName);          //find and call the RunScript function          PyObject *fnRun = PyObject_GetAttrString(onKeyPressModule, "Run");          if(fnRun)          {               boost::python::call<void>(fnRun, boost::python::ptr(e), boost::python::ptr(data));          }          else          {               std::cout << "Couldn't find Run function!\n";          }          Py_DECREF(fnRun);          Py_DECREF(onKeyPressModule);     }     catch( boost::python::error_already_set )     {          PyErr_Print();     }}

#### Share this post

##### Share on other sites
Thanks! I understand that code, and it works wonders.

However, it still think that there should be an easier way. If there's some other ways, please let me know!

#### Share this post

##### Share on other sites

• Advertisement
• Advertisement

• ### Popular Contributors

1. 1
2. 2
Rutin
18
3. 3
4. 4
5. 5
• Advertisement

• 14
• 9
• 9
• 9
• 10
• ### Forum Statistics

• Total Topics
632918
• Total Posts
3009204
• ### Who's Online (See full list)

There are no registered users currently online

×

## 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!