Home > Software engineering >  How to call Python from C ?
How to call Python from C ?

Time:03-02

From the docs :

cppyy is an automatic, run-time, Python-C bindings generator, for calling C from Python and Python from C .

(Emphasis mine)

I don't see any instructions for doing the same, however, so is it possible to call Python via C using cppyy?

CodePudding user response:

As a qualifier, since I don't know from where you obtained cppyy, the main code that was at the time the reason for typing that sentence does not exist in cppyy master, but does exist in its historic home of PyROOT. This so-called "class generator" plugin allows Cling to "see" Python classes as C classes, for straightforward callbacks and even inheritance of C classes from Python ones. See this publication (page 3) for some examples: https://www.researchgate.net/publication/288021806_Python_in_the_Cling_World

This code was not ported over to cppyy standalone b/c the class generator relies on interactive use (specifically, dynamic scopes), so only works from Cling, not compiled code, and there is no way (yet) to drop into the Cling prompt from Python (vice versa works).

The reason why that sentence is still there even without the class generator, is that cppyy has since grown a multitude of other ways to call Python from C (these have been backported into PyROOT). Examples include C-style function pointers, C std::function<> objects, lambdas, and cross-language inheritance. Moreover, these can all be used by importing cppyy into embedded Python (and thus be used from compiled C ).

See e.g. these examples in the documentation: callbacks and cross-inheritance. Cross-inheritance is probably the easiest to use: just define an abstract interface, implement it in Python, pass the pointer to C and use it like you would with any pointer-to-interface in C . For callbacks, declare an extern function pointer (or std::function object) in a header, pass that in a cppyy.include in embedded Python, assign a Python function to that pointer, then call it in C as desired.

Callbacks can be made quite sophisticated, assuming that the C side can handle it. For example, by providing annotations on the Python side, Python functions can instantiate C function pointer templates. Take the completely generic callback in C below, which accepts any arguments and producing any result:

>>> import cppyy
>>> cppyy.cppdef("""\
... template<typename R, typename... U, typename... A>
... R callT(R(*f)(U...), A&&... a) {
...    return f(a...);
... }""")
True
>>> def f(a: 'int') -> 'double':
...     return 3.1415*a
...
>>> cppyy.gbl.callT(f, 2)
6.283
>>> def f(a: 'int', b: 'int') -> 'int':
...     return 3*a*b
...
>>> cppyy.gbl.callT(f, 6, 7)
126
>>>

The final way of calling from C into Python is indeed not documented b/c it is (still) only available for CPython/cppyy, not PyPy/_cppyy and the naming is implementation-specific as well: CPyCppyy/API.h.

This header is meant to be included in C code, allowing the boxing and unboxing of cppyy-bound instances from C , custom converters and executors, memory management, and parameter packing for stub functions. There are also a couple of convenience functions for dealing with one-offs. For example:

import cppyy

def pyfunc():
    return 42

cppyy.cppdef("""\
#include "CPyCppyy/API.h"

int cppfunc() {
    return (int)CPyCppyy::Eval("pyfunc()");
}""")

print(cppyy.gbl.cppfunc())

(although the example here is run from Python for convenience, this can all be called from embedded Python in compiled C as well).

CodePudding user response:

I'm pretty sure cppyy only allows you to call C via Python, not vice versa. You could use Python.h, or use C to execute a python file as you would an .exe file, but that would require that the computer can run python files.

CodePudding user response:

I do not know if it answer to your question (from your title I understand that you want to call python function from c side, but later it seems you ask specifically about cpppy) but you can do the binding with pybind11. This package is heavily used and is being used in a lot of case as an alternative to swig (to understand the differences have a look at this open thread in the TensorFlow community). These are the two most used packages for Python-C binding.

To see how to call a python function in C for Pybind11 have a look at this question, while to see how to call a python function in C for swig have a look at this question.

  • Related