Why won't this work???

Michael P. Reilly arcege at shore.net
Thu Jun 3 14:21:30 CEST 1999


Jr. King <n at n.com> wrote:
: I know you are getting tired of me, but I have tried repeatedly to solve
: this on my own and I can't get it to work.
: I am trying to do a python callback to call from a c/c++ program.
: Here is the c/c++ code

: // learnPyth.cpp : Defines the entry point for the console application.
: //

: #include "stdafx.h"
: #include "python.h"
: #include "stdio.h"
: #include <iostream.h>
: #include <windows.h>

: static PyObject *my_callback = NULL;

: static PyObject* Test(PyObject *self, PyObject* args){
:  cout<<"Test"<<endl;
:  int command;
:  int aoe;
:     if (!PyArg_ParseTuple(args, "ii", &command,&aoe))
:         return NULL;

:  int xs(5);
:  PyObject* xarg = Py_BuildValue("(i)",xs);

:  PyEval_CallObject(my_callback, xarg);//python returns the PYNone thingie
: here
:  Py_DECREF(xarg);

:  return args;
: }

: static PyObject* setCallback(PyObject *self, PyObject* args){
:     PyObject *result = NULL;
:     PyObject *temp;

:     if (PyArg_ParseTuple(args, "O:set_callback", &temp)) {
:         if (!PyCallable_Check(temp)) {
:             PyErr_SetString(PyExc_TypeError, "parameter must be callable");
:             return NULL;
:         }
:         Py_XINCREF(temp);         /* Add a reference to new callback */
:         Py_XDECREF(my_callback);  /* Dispose of previous callback */
:         my_callback = temp;       /* Remember new callback */
:         /* Boilerplate to return "None" */
:         Py_INCREF(Py_None);
:         result = Py_None;
:     }
:     return result;
: }

: static PyMethodDef meths[]={
:  {"testmeth", Test, METH_VARARGS},
:  {"setCallback", setCallback, METH_VARARGS},
:  {NULL,  NULL}  /* sentinel */
: };

: int main(int argc, char* argv[])
: {
:  Py_Initialize();
:  char input[200];
:  int ret;
:  FILE *fp;
:  cout<<Py_GetPath()<<endl;
:  fp = fopen("beer.py","r+");
:  Py_InitModule("testmeth", meths);
:  Py_InitModule("setCallback",meths);
:  if(fp == NULL)
:   cout<<"Didn't open file";
:  else{
:   ret = PyRun_AnyFile(fp,"beer.py");
:   cout<<ret<<endl;
:   fclose(fp);
:   Py_Exit(0);
:  }
:  return 0;
: }

: Here is the python code

: #! /usr/bin/env python
: # By GvR, demystified after a version by Fredrik Lundh.
: #import sys
: import testmeth
: import setCallback
: n = 20
: #if sys.argv[1:]: n = int(sys.argv[1])

: def setN(x):
:  x = n
:  print n

: def bottle(n):
:     if n == 0: return "no more bottles of beer"
:     if n == 1: return "one bottle of beer"
:     return str(n) + " bottles of beer"

: setCallback.setCallback(setN)
: testmeth.testmeth(13,9)
: for i in range(n):
:     #print bottle(n-i), "on the wall,"
:     #print bottle(n-i) + "."
:     #print "Take one down, pass it around,"
:     print bottle(n-i-1), "on the wall."

: print n

: thanks again.

To be honest, what you think the "error" is here is quite confusing
from your output.  But your comment in the Test() function mentions
that PyEval_CallObject() returns Py_None from setN.  This would be correct,
since a function with no "return" statement would return None (Py_None)
(cf. section 5.3.4 "Calls" in the Python Reference Manual).

But what you do want to do is capture the return value from
PyEval_CallObject to at the very least decrement the reference count
(with Py_DECREF) or to see if there was an exception (NULL).

In addition, you return the argument list passed to the function, this
argument list is owned by the calling C routine and will its reference
count will be decremented (most likely to zero, thereby destroying the
object) when Test() returns.  If you are going to return the argument
list, then you will want to increment the reference count.

  static PyObject* Test(PyObject *self, PyObject* args) {
    cout<<"Test"<<endl;
    int command;
    int aoe;
++  PyObject *res;
    if (!PyArg_ParseTuple(args, "ii", &command,&aoe))
      return NULL;

    int xs(5);
    PyObject* xarg = Py_BuildValue("(i)",xs);

    //python returns the PYNone thingie here
++  res = PyEval_CallObject(my_callback, xarg);
    Py_DECREF(xarg);
++  if (res == NULL) /* propagate the exception raised */
++    return NULL;
++  Py_DECREF(res);

++  Py_INCREF(args);
    return args;
  }

Hope this helps,
  -Arcege





More information about the Python-list mailing list