Dear enthusiasts,
Apologies in advance for my use of pseudo-code below, but I hope it conveys what I want to achieve clearly enough.
I have a custom C++ class with a template (called TData
) function that I would like to run from PyROOT that takes a vector of strings as argument names to be processed:
// MyHelper.h
struct MyHelper
{
template <typename T>
void myAction(const std::string& name, const std::vector<std::string>& args);
};
...
// myCode.cxx
auto helper = MyHelper();
helper.myAction<TData>("doSomething",{"thing1","thing2"}); // great! want to do this in PyROOT
Via PyROOT, I would like to be able to call this as “minimal” as possible:
# myCode.py
import ROOT
helper = ROOT.MyHelper()
helper.myAction[ROOT.TData]("doSomething",['thing1','thing2'])
# Unfortunately not possible, as conversion from list to vector is ill-formed?
The basic issue here I face here is that I would like to be able to supply a simple list/tuple as the second argument, which isn’t possible. The workarounds that I’ve considered are:
- template parameter pack arguments
// MyHelper.h
struct MyHelper
{
// use template paramter pack instead of vector
template <typename T, typename... Args>
void myAction(const std::string& name, Args... args);
};
# myCode.py
helper.myAction[ROOT.TData]("doSomething",'thing1','thing2')
# This would be nice, PyROOT template parameter deduction does not seem to quite work reliably here
helper.myAction[ROOT.TData,ROOT.std.string,ROOT.std.string]("doSomething",'thing1','thing2')
# This works, but ends up being very verbose
- a python function to convert list to vector
helper.myAction[ROOT.TData]("doSomething",vectorize(['thing1','thing2']))
# Annoying to have to wrap vectorize() everytime...
- #2 + Pythonization of the class
# MyHelper.py
class MyHelper(ROOT.MyHelper):
def __init__(self):
ROOT.MyHelper.__init__(self)
# re-define myAction to call the base class one with proper arguments
def myAction(self,dataType): # provide dataType as first function argument
def myActionWithDataType(name,args): # nested function accepting the name and *list* of arguments
ROOT.MyHelper.myAction[dataType](self,name,vectorize(args)) # vectorization of list from #1
return myActionWithDataType
# myCode.py
helper = MyHelper.MyHelper()
helper.myAction(ROOT.TData)("doSomething",["thing1","thing2"])
# This achieves the minimal interface that I want as long as I provide such a python wrapper for every single function that I write.
# Is it bad to "regress" to using the () brackets instead of [] for the template parameter?
An analogous discrepancy in C++/PyROOT functionality I can find is the RDataFrame::Define()
method, where in C++ one can supply a vector of strings as column names to be processed as arguments to the definition, but from PyROOT one can only call the one with an expression and no column names.
So far, #3 feels 95% satisfactory for me, the nitpick being that I am using ()
brackets instead of []
as they would ideally be for the template parameter. Would there be a better way that I might have missed, e.g. way to keep the []
brackets in the pythonized function?
Please read tips for efficient and successful posting and posting code
ROOT Version: 6.20.06