PyCFunction_New() ?

S

Scott Deerwester

Is it possible to create a Python-callable object, dynamically, in C/C++? I
have a GUI app in C++, with the app logic in Python, called from the
GUI via the Python C API. I need be able to call a callback function
in C/C++ from the Python, in response to an event (socket, whatever...)
that the Python is aware of. Callbacks in Python, called from C/C++
are very straightforward, but I haven't been able to find any examples
of the converse.

So I want to be able to do something like:

PyCFunction *myCallback(PyObject *ob, PyObject *args) { ... }

{
PyObject *somePythonObject;
...
PyObject *myCallbackObject = PyFunction_New(myCallback, ...);
PyObject_CallMethod(somePythonObject, "setCallback", myCallbackObject);
...
}

Even better would be:

PyCFunction *MyClass::pyCallback(PyObject *ob, PyObject *args) { ... }

MyClass::MyClass()
{
...
PyObject_CallMethod(somePythonObject, "setCallback", this->pyCallback);
...
}

Any help greatly appreciated!
 
A

Alex Martelli

Scott Deerwester said:
Is it possible to create a Python-callable object, dynamically, in C/C++? I

Sure! But I'm not clear on why you want to create it dynamically. The
C++ code is there all the time, isn't it? So why not the wrapping of it
into Python-callable terms...?
Even better would be:

PyCFunction *MyClass::pyCallback(PyObject *ob, PyObject *args) { ... }

MyClass::MyClass()
{
...
PyObject_CallMethod(somePythonObject, "setCallback", this->pyCallback);
...
}

Here pyCallback _returns_ a pointer to a PyCFunction, yet you want to
SET it as the callback...? I'm confused! Also, PyObject_CallMethod
needs a format string as its 3rd arg, before the args 'proper' -- do you
intend to omit it? Why? Again, I'm confused.
Any help greatly appreciated!

You can call PyCFunction_New, passing it a first argument that's a
PyMethodDef struct pointer, and a 2nd argument that's a PyObject*
(whatever you want the C function to receive as the first argument,
self). PyMethodDef is, of course:

struct PyMethodDef {
char *ml_name;
PyCFunction ml_meth;
int ml_flags;
char *ml_doc;
};
typedef struct PyMethodDef PyMethodDef;

What problems is this giving you...?


Alex
 
S

Scott Deerwester

Alex said:
Sure! But I'm not clear on why you want to create it dynamically. The
C++ code is there all the time, isn't it? So why not the wrapping of it
into Python-callable terms...?

Because I'd like to have multiple instances of the class that has (or is
somehow associated with) the C/C++ callback, and to be able to hand a
corresponding Python object a Python-callable callback that ends up
invoking the C++ callback for a particular C++ class instance...

That's a lot of words, but the intention is:

CObj1 = new SomeClass();
/* CObj1 constructor instantiates a Python SomePyClass object PObj1 */
/* CObj1 calls PObj1.setCallback(CObj1->someMethod) */
CObj2 = new SomeClass();
/* CObj2 constructor instantiates a Python SomePyClass object PObj2 */
/* CObj2 calls PObj2.setCallback(CObj1->someMethod) */

....

# PObj1 decides to call its callback, which calls CObj1->someMethod()

# PObj2 decides to call its callback, which calls CObj2->someMethod()

So the C++ function is (of course) not dynamic, but the Python object
that wraps it is.
You can call PyCFunction_New, passing it a first argument that's a
PyMethodDef struct pointer, and a 2nd argument that's a PyObject*
(whatever you want the C function to receive as the first argument,
self). PyMethodDef is, of course:

struct PyMethodDef {
char *ml_name;
PyCFunction ml_meth;
int ml_flags;
char *ml_doc;
};
typedef struct PyMethodDef PyMethodDef;

What problems is this giving you...?

I was getting confused between a PyCFunction (which isn't a PyObject,
is it?) and PyCFunction_New... which isn't in the API documentation.

I'll have at it with what you've given me. Thanks!
 
A

Alex Martelli

Scott Deerwester said:
Because I'd like to have multiple instances of the class that has (or is
somehow associated with) the C/C++ callback, and to be able to hand a
corresponding Python object a Python-callable callback that ends up
invoking the C++ callback for a particular C++ class instance...

Ah, you want to make "bound methods" from C++...? That's a tall order
indeed. In C++ itself, in fact, you couldn't.

Fortunately, you can exploit the 2nd argument of PyCFunction_New. Place
the pointer to the C++ object there, wrapped into a PyObject (or cast
into a PyObject* if you feel frisky...!-). Your C function unwraps it
or casts it back, and then can call the C++ method on the suitable
instance thus recovered.


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top