Integrating Python and C

[ LiB ]

Integrating Python and C++

I hope that my little crash course on Python was enough to give you a general feel for the language. I have to admit, I picked up basics of the language in about two to three days, since the concepts are all very similar to those of C++ (and all other object-oriented imperative languages), so I doubt you'll have any problems.

Now, on to the difficult partintegrating C++ and Python. The good news is that the Python language was originally made in C, so that gives us a nice platform to start with.

NOTE

If you ever have a question about Python, there is great free documentation available at http:// www.python.org . As of this writing, there's a great tutorial to the lan guage here: http://www.python.org/ doc/current/tut/tut.html .

The Python-C API is very easy to use, and is well documented as well. As of this writing, you can access the documentation for the Python-C API at this address: http://www.python.org/doc/current/api/api.html.

Demo 17.1Making An Interpreter

The first demo I want to show you is an example of how easy it is to integrate the Python interpreter into your C++ program.

You can find this demo on the CD in the directory /Demos/Chapter17/Demo17-01/ on the CD. To compile the demo, set up your compiler as described in Appendix A, which is also on the CD.

I'm going to spit all the code out at you at once, but I don't think you'll mind, since it's really simple:

 #include <iostream> #include <string> #include "Python.h" int main() {     std::cout << "Welcome to SIMPLEPYTHON!!" << std::endl;     std::cout << "Chapter 17, Demo 01 - MUD Game Programming" << std::endl;  Py_Initialize();                // initialize python  std::string str;     std::getline( std::cin, str );  // get each line     while( str != "end" ) {         // exit if you got "end"  PyRun_SimpleString( const_cast<char*>( str.c_str() ) );  std::getline( std::cin, str );     }  Py_Finalize();                  // shut down python  return 0; } 

The three calls to Python functions in the code are marked in bold. The first call initializes the Python interpreter, the second tells it to execute a string, and the final call tells the Python interpreter to shut down.

Figure 17.4 shows the SimplePython interpreter in action.

Figure 17.4. SimplePython in action.

graphic/17fig04.gif


When I first got this working, I had two thoughts:

  1. WOW! THIS IS SO COOL!!

  2. Hey, I can't believe I made this in less than two minutes!

See how easy it is to get Python code up and running in your programs?

NOTE

C++ std::string s cannot be con verted into char* pointers implicitly, so to accomplish that you must call their c_str function. However, the function returns const char* s, and Python, for some oddball reason, accepts only non- const char* s as parameters to the functions. So in order to properly pass an std::string into the function, I need to cast away its const characteristics first.

Demo 17.2Python Objects

That first example was quite simple, and really only concerned the execution of Python code from a string. If you want to do anything more complex, you'll have to mess around with the internals of Python.

Everything in the API is based on the idea of a Python Object , which is a structure that points to an object that is being used within Python. This code

 x = 10 

creates a new Python object, entitled x , and it holds an integer value of 10. Creating a class creates a new Python object that contains the definition of a class, and creating an instance of that class creates yet another Python object.

Python objects are stored in a simple structure called PyObject . They are large and fairly complex, but luckily, you should never have to deal with them, except to pass them to and from Python-C API functions. Here is a simple example, which loads a file containing Python code:

 PyObject* mod = PyImport_ImportModule( "pythontest" ); 

After this code has been called, mod should be pointing to a Python object that represents the module pythontest , which was loaded from the file pythontest.py. Python automatically assumes modules end with a .py suffix.

NOTE

Python modules can contain code that is outside functions or classes. This code is executed when the module is first loaded, so the mo ment you load it up, THIS IS A TEST OF PYTHON!!!! should be enthusiastically printed to your console window. Modules can also have variables , as shown by the x = 10 line.

Python Test Module

Now, what can you do with this module? You can actually do anything you want. Let me show you what's in the module first though:

 print "THIS IS A TEST OF PYTHON!!!!" x = 10 def testfunc():     print "TEST FUNCTION!!" def printfunc( arg ):     print arg def returnstring():     return "HELLO C++!!" 

Running the Code from Python

Once you have that loaded, you can execute Python code:

 PyRun_SimpleString( "import pythontest\n"                     "pythontest.testfunc()\n" ); 

This imports the module into the namespace of the PyRun_SimpleString function, and then calls its testfunc function, which should print TEST FUNCTION!! to your console.

Running the Code from C++

Now that you can call stuff using a simple string, try the slightly more complex operation of calling it directly from C++:

 PyObject* result =     PyObject_CallMethod( mod, "testfunc", null ); 

NOTE

It should be noted that since you're importing the function inside the call to PyRun_SimpleString , you don't actually have to import the module in C using PyImport_ImportModule first. But since I plan on using the module later on, I load it anyway.

This calls the test function from mod with no parameters. Since the function doesn't return anything either, why the heck did I record the result? This is one of the little quirks of Python. Even if you return nothing, the language internally returns the null object . Of course, if it's a null object, you can just ignore it right?

Wrong. Everything in Python is reference counted, which means that the Python-C API tries to track the number of places in the program that are referencing any given Python object. Whenever the reference count drops to 0, the Python-C API knows that it is safe to delete the object. If you accidentally still have it after it has been deleted, you're going to be accessing an invalid object, and you'll be in big trouble.

The PyObject_ functions always return new references to Python objects, which means that the null reference count of the object that was returned from this function increased. It is up to you to remove one from its reference count like this:

 Py_DECREF( result ); result = 0; 

You're telling Python that you've finished pointing to that object, and that you won't be referencing it anymore. Therefore it's a good idea to clear the pointer as well.

This can get tricky, so later I'll show you my Python wrapper that takes care of this stuff for you.

NOTE

For each function in the API, the Python-C API documentation lists references as new or borrowed . Whenever you call a function that returns a borrowed reference, you're not supposed to decrease its refer ence count at all. This can make managing objects somewhat difficult, but luckily, there aren't many func tions that return borrowed refer ences. In fact, in my Python wrapper, I never use any of those functions, so I can safely assume that all pointers need to be dereferenced.

Calling Functions with Parameters

Now we can try something more complicated, calling a function with a parameter:

 result = PyObject_CallMethod( mod, "printfunc", "s", "HELLO PYTHON!" ); Py_DECREF( result ); result = 0; result = PyObject_CallMethod( mod, "printfunc", "i", 42 ); Py_DECREF( result ); result = 0; 

This calls the printfunc function with a string, and then with an integer, which should print them both.

Getting Results

On the other side of the equation, you're going to need to extract return values from Python objects. This is a relatively painless task to accomplish, because Python contains tons of built-in functions for converting the basic types from objects. This time, we're going to call returnstring :

 result = PyObject_CallMethod( mod, "returnstring", null );  std::string str = PyString_AsString( result );  std::cout << str << std::endl; Py_DECREF( result ); result = 0; 

The line in bold is the function that converts a Python object to a C++ char* object, which I then promptly copy into a std::string .

You need to be careful when using the PyString_AsString function. It returns a char* , which is a pointer, but Python still owns the buffer it points to. You shouldn't modify it at all or try to delete it. In fact, the safest, sanest thing to do is to copy the contents of the buffer into a string of your own right away , because Python may even modify the buffer later on, or deallocate it without telling you (how rude!).

NOTE

The char* s of C are the devil . I have never seen a more evil invention in my life. Well maybe the Oscar Meyer Weeniemobile, but I don't think that counts. Use std::string of C++ instead.

All the code in this section is compiled into Demo 17.2 on the CD, which you compile in the same way as Demo 17.1. When you run it, it should produce output like this:

 Python Test! Chapter 17, Demo 02 - MUD Game Programming THIS IS A TEST OF PYTHON!!!! TEST FUNCTION!! TEST FUNCTION!! HELLO PYTHON! 42 HELLO C++!! 

That's it for this demo.

[ LiB ]


MUD Game Programming
MUD Game Programming (Premier Press Game Development)
ISBN: 1592000908
EAN: 2147483647
Year: 2003
Pages: 147
Authors: Ron Penton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net