简体   繁体   中英

Embedding python in cpp: How to get a C-pointer to a python function (not to a PyObject)?

I want to enable the writing of user python-plugins for an existing C++ application. The main application will emit signals using boost::signals2 that trigger the execution of the users python code. I set up a working sample where an initialize method in the users python module is being called. The user can subscribe to signals calling a "connect"-method:

import ctypes
CALLBACK_VOID_FUNC = CFUNCTYPE(None)

def myVoidHandler():
    print("myVoidHandler (python)")

def initialize(myCHandle):
    global myCDll, callback1
    myCDll = ctypes.CDLL("CppEventsd",  handle = myCHandle)
    [...]
    callback1 = CALLBACK_VOID_FUNC(myVoidHandler)
    myCDll.connect(b"readyToGo", callback1)
    [...]

The signature of the connect method:

extern "C" __declspec(dllexport) bool connect(char* signalName, void(*pF)())

Now the python function myVoidHandler could be called from cpp just like this:

pF();

But more importantly, pF can be connected to a boost signal.

However I want to spare the users going through this (and spare myself the support requests because they did not get it quite right), so I want to connect the python functions from the cpp side by using a naming convention for the functions/slots. I can easily retrieve a PyObjet pointer to the python callback:

PyObject *pModule, *pDict, *pVoidHandlerF;
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pVoidHandlerF = PyDict_GetItemString(pDict, "myVoidHandler");

BUT I cannot figure out how to get the actual function pointer (equivalent to pF) from the cpp side! Some transformation seems to be going on in the python to Cpp transition.

Any ideas?

Instead of connecting directly to the python function pointer, you could create your own C++ function that uses the python C-API to invoke the python function. Here is an example:

boost::signals2::signal<void(void)>& sig = [...];
PyObject* pVoidHandlerF = [...];
sig.connect([=]() {
    PyObject_CallObject(pVoidHandlerF, NULL);
});

This allows you to do other stuff on the C++ side, for example, passing arguments, returning values, checking for errors, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM