Pybind11: How can i call a python function inside c++ using pybind11?

Created on 20 Mar 2017  路  17Comments  路  Source: pybind/pybind11

Hy Developers,

How can i call a python function inside C++? I found a closed issue (https://github.com/pybind/pybind11/issues/30) where this question was asked by @skebanga but it seems that his question was not fully answered.

For example: I have a python function myfun

def myfun(i, j):
out = i + j
return out

Now i would like to call this function inside visual studio 2015. How can i do this? :P
I read the docs and tried to figure out how the test_callbacks.cpp/test_callbacks.py works but i really dont get it. Is there somewhere else a simple example how to do this?

Thank you for your help!

Most helpful comment

You could do this as follows:

auto module = py::reinterpret_borrow<py::object>(myModule);
auto myFunc = module.attr("PrintObject");
myFunc(<arguments>);

By the way: if you're going to let out your frustration here, then please do use Boost.Python instead. This is a free product developed by volunteers, and nobody is forcing you to use it.

All 17 comments

pybind11 doesn't officially support embedding python in C++ (or didn't when I last looked at it)

However, it is possible.

I wrote a blog post about doing this which might be helpful to you.

Please note I would suggest reading this blog post first, as it gives context to the other one. (It's about embedding python using boost::python)

All that said, you might want to consider using boost::python, where embedding is supported.

HTH

Ok thanks for this information! :)
But whats about this test_callbacks.cpp/test_callbacks.py examples in tests directory? I thought this example would deal with that question? See http://pybind11.readthedocs.io/en/master/advanced/pycpp/object.html

The documentation mentions the following but doesn't mention how to get a function.

Calling Python functions

It is also possible to call python functions via operator().

py::function f = <...>;
py::object result_py = f(1234, "hello", some_instance);
MyClass &result = result_py.cast();

I'm doing the following and it just keeps crashing (due to it attempting to access something 8 bytes into a structure that pointed to by a null pointer):

    PyObject* myFunc = PyObject_GetAttrString(myModule, "PrintObject");

    if (myFunc == nullptr) {
        PyErr_Print();            
        return 0;
    }

    printf("%p\n", (void*)myFunc);

    py::object func = py::cast(myFunc);

    func();

I need to be able to call into Python and pass C++ instantiated objects to embedded Python, where Python can then use to set and get properties on those objects.

You could do this as follows:

auto module = py::reinterpret_borrow<py::object>(myModule);
auto myFunc = module.attr("PrintObject");
myFunc(<arguments>);

By the way: if you're going to let out your frustration here, then please do use Boost.Python instead. This is a free product developed by volunteers, and nobody is forcing you to use it.

Sorry, I removed my frustration from the comment. It has been a very trying day for me and I'm racing to finish this for a deadline and let it get the better of me.

Thanks for the response this is now working for me:

salah@Europa:~/Enlistments/scratch2/testpythoninterface$ ./pythontest
Bob

    auto module = py::reinterpret_borrow<py::object>(myModule);
    auto myFunc = module.attr("PrintObject");

    Pet myPet("Bob");

    myFunc(myPet);

with the following python code:

import pythontest

def PrintObject(object):
    print(object.getName())

You might also get myModule as a py::module directly (i.e. instead of as a raw CPython pointer) with auto myModule = py::module::import("package");, in which case you don't need the reinterpret_borrow.

(For pretty much all common things, it shouldn't be necessary to touch the C API directly).

Thanks, I switched over to that for the module and it's now working.

I still seem to need to do this to get it to find the module though:

PyRun_SimpleString("import sys\nimport os\nsys.path.insert(0,os.getcwd())\n");

Is there some other way I could do so?

Untested, but I think you could use:

py::reinterpret_borrow<list>(PySys_GetObject("path")).append(".");

or you could also import both via py::module::import and do the equivalent without touching the C API.

I suggest to move further discussion to Gitter, since this is not a pybind11 bug.

Looks like this issue has been resolved here. In addition, #774 should resolve issues with embedding support and the new documentation page includes a specific example of calling a Python function in C++.

@Salahuddin-Khan
hey you said that below is working for you.
auto module = py::reinterpret_borrow<py::object>(myModule);
auto myFunc = module.attr("PrintObject");
could you please tell me how you include that python file into the main program?
p.s im new here

In my case, the python module is being used for a plug in. I initialize it as follows:

The PlugInModuleName is the name of the python module that is actually utilized. I have some initialization code that adds the path to the plug-in module so that it can be found during initialization.

void CPythonInterface::InitializePlugIn(std::string PlugInPath, std::string PlugInModuleName)
{
    std::string plugInInitCode;
    Py_Initialize();
    pybind11_init();

    plugInInitCode = "import sys\nimport os\nsys.path.insert(0,\"";
    plugInInitCode += PlugInPath;
    plugInInitCode += "\")";

    PyRun_SimpleString(plugInInitCode.c_str());
    m_Module = module::import(PlugInModuleName.c_str());
    m_InvokePlugIn = (py::function) m_Module.attr("InvokePlugIn");

    m_Initialized = true;
}

The actual invocation code is similar to this:

void CPythonInterface::InvokePlugIn(TaskInformation* Task,
                                           std::string PlugInName,
                                           PlugInOperation::Type OperationType,
                                           IInterfacePlugInData* Data)
{
    m_InvokePlugIn(Task, PlugInName.c_str(), OperationType, Data->GetTargetName().c_str(), Data);
}

I hope this helps.

-s

@Salahuddin-Khan
Thanks alot for the help, i got it working.
cheers!

Hi,
I have a similar question. I have a usecase where I have implemented an API in python and it needs to return struct, vector or map to C++. Could you please help me with an example how to do that. All the usecases I see in pybind is just simply python being embedded in C++ without any return value.
I am in a time-bound project and looking forward to quick responses.

You could do this as follows:

auto module = py::reinterpret_borrow<py::object>(myModule);
auto myFunc = module.attr("PrintObject");
myFunc(<arguments>);

By the way: if you're going to let out your frustration here, then please do use Boost.Python instead. This is a free product developed by volunteers, and nobody is forcing you to use it.

@wjakob Is it possible to pass the pointer of the C++ data type to the loaded modules
(for ex; std::vector U ; myFunc (& U)). I have seen the examples in the doc on Type conversion (https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html) but all the examples describes the C++ routine wrapped with pybind and called in the Python program. I was looking for examples where the python is embedded into C++ program as you described above and a an access to C++ data structure can be done without copying. BTW I have successfully used the automatic method defined by "#include " Your suggestion or comments will be really helpful.
Thank you

Was this page helpful?
0 / 5 - 0 ratings