Home | News | Documentation | Download

Calling Python function from C++

I recall somewhere saying that ROOT supports calling Python functions from C++ by converting functions into std::function. Is this information correct? If it is, how can I do so? My experiments kept failing.

I have tried passing a lambda as a std::function. It doesn’t work

>>> import ROOT
>>> gROOT = ROOT.gROOT
>>> gROOT.ProcessLine("int foo(function<int(int,int)> f) { return f(1, 1); }")
0
>>> ROOT.foo(lambda a, b: a+b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: int ::foo(function<int(int,int)> f) =>
    could not convert argument 1

Template also doesn’t work

>>> import ROOT
>>> gROOT = ROOT.gROOT
>>> gROOT.ProcessLine("template <typename T>int foo(const T& f) { return f(1, 1); }")
0
>>> ROOT.foo(lambda a, b: a+b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can not resolve method template call for 'foo'

Nor function pointers work

>>> import ROOT
>>> gROOT = ROOT.gROOT
>>> gROOT.ProcessLine("using func_t = int(int,int);")
0
>>> gROOT.ProcessLine("int foo(func_t f) { return f(1, 1); }")
0
>>> ROOT.foo(lambda a, b: a+b)
<stdin>:1: RuntimeWarning: creating converter for unknown type "int(int,int)"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: int ::foo(int(int,int) f) =>
    could not convert argument 1

What am I doing wrong?

Hi Martin,
I don’t think that’s correct. The other way around (calling C++ functions from python) works transparently for most simple cases. To invoke python functions you need all of python’s context (and you need to do it through a python interpreter, because in general there is no binary that C++ can hook into). That’s what TPython::Eval and TPython::Exec help with (docs here), and for simple return types Eval actually does what you need.

Hope this helps,
Enrico

A priori, you’re going to need experimental_pyroot, but although it supports conversion to std::function and to C-style function pointer, it does not do so for templates (i.e. python callable -> std::function is not considered when matching the template). Is a good idea, though.

Thank you all. Seems I got my information from a slide on the internet not realizing it is in the experimental branch.