[PyKDE] SIP vs Boost.Python?

Niac Neb niacneb at yahoo.com
Thu May 12 18:46:44 BST 2005


James,

Invoking Python calls from C++ is very tedious and
error prone.  To me this signifies a prime candidate
for simplification and encapuslation.  Perhaps most
people only extend Python with C++.  As I've said, I
need C++ to be the main loop (for very good reasons)
and to envoke Python calls where prudent.

Attached is a "simple" (admitedly contrived) example
of The Python/C API.  ALL it does is call Python to
multiply two numbers and return the result.  IMHO this
is VERY, VERY difficult to code to ... much effort is
required.  One has to be especially careful with
resource allocation/cleanup, variable argument list
setup, exception handling, type safety, ... Wow!  The
function and argument list formulation seemed the most
tedious to me.  This example was only for one specific
function and type parameters.  The general case makes
me cringe.

So, it seems to me there is a need.  But, perhaps I
misunderstand.

Thanks

--- James Emerton <ephelon at gmail.com> wrote:
> There is no need for SIP to be enhanced to handle
> this.  (I don't
> think boost::python has anything special here
> either.)  The Python API
> can be made available by linking your application to
> the correct
> library and calling Py_Initialize().
> 

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 
-------------- next part --------------
////////////////////////////////////////////////////////////////////////////////
// Filename       : mult.cpp
//
// Description    : Example of C++ code calling a Python script.  The C++ code
//                  passes two numbers to the Python script.  The Python script
//                  multiplies these two numbers and returns the result to the
//                  calling C++ code.
//
// Example:
//   mult 7.1 3.2
// Example output:
//   7.1 * 3.2 = 22.72
//
// Revision History:
//   Date       Name   Description
//   04/21/05   BRC    Initial Release
//
////////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <string>
#include <cstdlib>

#include "python.h"

using std::cout;
using std::cerr;
using std::endl;

namespace Python
{
   bool LoadFunction(std::string module, std::string func,
      PyObject ** pyModule, PyObject ** pyFunc);
   void UnloadFunction(PyObject ** pyModule, PyObject ** pyFunc);
   bool SetArgs(double operands[2], PyObject ** pyArgs, PyObject ** pyValue);
   void UnsetArgs(PyObject ** pyArgs, PyObject ** pyValue);
} // Python


////////////////////////////////////////////////////////////////////////////////
int main(int argc, char ** argv)
////////////////////////////////////////////////////////////////////////////////
{

   if(argc < 3)
   {
       cout << "Usage\n\t mult [num1] [num2]\n";
       return EXIT_FAILURE;
   }

   std::string pythonFile("mult");
   std::string pythonFunc("mult");

   double operands[2];
   operands[0] = atof(argv[1]);
   operands[1] = atof(argv[2]);

   // Startup the Python interpreter and allocate necessary resources.
   Py_Initialize();

   // Load python function.
   PyObject * pName(0);
   PyObject * pyFunc(0);
   PyObject * pyModule(0);
   if(Python::LoadFunction(pythonFile, pythonFunc, &pyModule, &pyFunc) == false)
      return EXIT_FAILURE;

   // Set python arguments.
   PyObject * pyValue(0);
   PyObject * pyArgs(0);
   if(Python::SetArgs(operands, &pyArgs, &pyValue) == false)
   {
      // Free resources.
      Python::UnloadFunction(&pyModule, &pyFunc);
      return EXIT_FAILURE;
   }

   // Call python function.
   pyValue = PyObject_CallObject(pyFunc, pyArgs);
   Py_DECREF(pyArgs);
   if(!pyValue)
   {
      // Free resources.
      Python::UnloadFunction(&pyModule, &pyFunc);
      PyErr_Print();
      cerr << "Python call failed!" << endl;
      return EXIT_FAILURE;
   }
   double result = PyFloat_AsDouble(pyValue);

   // Output python function's results.
   cout << operands[0] << " * " << operands[1] << " = " << result << endl;

   Python::UnloadFunction(&pyModule, &pyFunc);
   Python::UnsetArgs(&pyArgs, &pyValue);

   // Shut down the Python interpreter and free allocated resources.
   Py_Finalize();

   return EXIT_SUCCESS;
} // main


////////////////////////////////////////////////////////////////////////////////
bool Python::LoadFunction(std::string module, std::string func,
   PyObject ** pyModule, PyObject ** pyFunc)
////////////////////////////////////////////////////////////////////////////////
{

   *pyFunc = 0;
   *pyModule = 0;

   PyObject * pName = PyString_FromString(module.c_str());
   *pyModule = PyImport_Import(pName);
   Py_DECREF(pName);
   if(!(*pyModule))
   {
      PyErr_Print();
      cerr << "Failed to load Python file, " << module << endl;
      return false;
   }

   // pyDict is a borrowed reference.
   PyObject * pyDict = PyModule_GetDict(*pyModule);
   // pyFunc is a borrowed reference
   *pyFunc = PyDict_GetItemString(pyDict, func.c_str());
   if(!(*pyFunc) || !PyCallable_Check(*pyFunc))
   {
      if(PyErr_Occurred())
         PyErr_Print();
      cerr << "Cannot find Python function, " << func << endl;
      Py_DECREF(*pyModule);
      *pyModule = 0;
      Py_Finalize();
      return false;
   }

   return true;
} //  Python::LoadFunction


////////////////////////////////////////////////////////////////////////////////
void Python::UnloadFunction(PyObject ** pyModule, PyObject ** pyFunc)
////////////////////////////////////////////////////////////////////////////////
{
   Py_DECREF(*pyModule);
   *pyModule = 0;
   // pyFunc is a borrowed reference ... no need to de-reference.
   *pyFunc = 0;
} // Python::UnloadFunction


////////////////////////////////////////////////////////////////////////////////
bool Python::SetArgs(double operands[2], PyObject ** pyArgs, PyObject ** pyValue)
////////////////////////////////////////////////////////////////////////////////
{
   *pyArgs = PyTuple_New(2);
   for(int i=0; i<2; i++)
   {
      *pyValue = PyFloat_FromDouble(operands[i]);
      if(!(*pyValue))
      {
         Py_DECREF(*pyArgs);
         cerr << "Cannot convert argument" << operands[i] << endl;
         return false;
      }
      // pyValue reference stolen here.
      PyTuple_SetItem(*pyArgs, i, *pyValue);
   }

   return true;
} // Python::SetArgs


////////////////////////////////////////////////////////////////////////////////
void Python::UnsetArgs(PyObject ** pyArgs, PyObject ** pyValue)
////////////////////////////////////////////////////////////////////////////////
{
   *pyArgs = 0;
   Py_DECREF(*pyValue);
   *pyValue = 0;
} // Python::UnsetArgs

-------------- next part --------------
################################################################################
## Filename       : mult.py
##
## Description    : Python script that multiplies two passed numbers and returns
##                  returns the result.
##
## Revision History:
##   Date       Name   Description
##   04/21/05   BRC    Initial Release
##
################################################################################

def mult(a,b):
   c = a * b
   return c

-------------- next part --------------
################################################################################
## Filename       : makefile
##
## Description    : Makefile for C++ example invoking embedded Python script.
##
## Revision History:
##   Date       Name   Description
##   04/21/04   BRC    Initial Release
##
################################################################################

TARGET = mult.exe

CC = g++

SRCS = mult.cpp

INCPATHS = \
   -I. \
   -IC:/Python23/include

LIBPATHS = -LC:/Python23/libs
LIBS = -lpython23

CFLAGS = -g
LDFLAGS =

OBJS = $(SRCS:.cpp=.o)

default: $(TARGET)

$(TARGET): $(OBJS) $(LDFLAGS)
	@echo "Linking $(TARGET) ..."
	g++ -o $(TARGET) $(OBJS) $(LIBPATHS) $(LIBS)
	@echo "... Done Linking $(TARGET)"

clean:
	rm *.o
clobber:
	rm *.o *.pyc $(TARGET)

.SUFFIXES: .o .cpp .c
.cpp.o:
	@echo Compiling $< [C++]
	$(CC) -c $(CFLAGS) $(INCPATHS) $< -o $@
.c.o:
	@echo Compiling $< [C++]
	$(CC) -c $(CFLAGS) $(INCPATHS) $< -o $@



More information about the PyQt mailing list