问题
Can someone suggest a way to manipulate c++ objects with Cython, when the c++ instance of one class is expected to feed the constructor of another wrapped class as described below?
Please look at the note on the pyx file for the class PySession, which takes a python PyConfigParams object as argument and then needs to extract values from it in order to construct a c++ ConfigParams object. the ConfigParams object is then used to feed the constructor of Session.
It would be ideal to have a procedure which would allow me to "inject" the ConfigParams c++ object wrapped by the PyConfigParams object directly into the constructor of Session, without having to dismantle it first and then building a new c++ object to feed the constructor. This works, of course. However, it is a cumbersome, sort of brutal way to implement this solution, not to mention unreliable.
I am aware of PyCapsule, however it may require to touch the c++ headers, which is something I can not do.
Related to this, but a different question is: what if I need a wrapped class (let's say here PySession) to simulate the behavior of the C++ api by returning a ConfigParams instance? would I need to do the reverse and dismantle the c++ object to build a Python PyConfigParams which would then be returned to the Python user in the Python world? Any suggestions are very welcome! Thank you!
Let's suppose I have two c++ classes named ConfigParams and Session. An instance of ConfigParams is used to feed the constructor of the Session class:
C++ classes
ConfigParams class
// ConfigParams.h
#include <iostream>
using namespace std;
class ConfigParams
{
int parameter1;
public:
ConfigParams(int par1) { this->parameter1 = par1;}
int getPar1() { return this->parameter1; }
};
Session class
// Session.h
#include <iostream>
using namespace std;
#include "configparams.h"
class Session
{
int sessionX;
public:
Session(ConfigParams parameters) { this->sessionX = parameters.getPar1(); }
void doSomething();
};
void Session::doSomething()
{
cout << "Session parameters set as: " << endl;
cout << "X = " << this->sessionX << endl;
}
Cython pyx and pxd files for the above classes:
PyConfigParams
# configparams.pxd
cdef extern from "configparams.h":
cppclass ConfigParams:
ConfigParams(int par1)
int getPar1()
# configparams.pyx
cdef class PyConfigParams:
cdef ConfigParams* thisptr
def __cinit__(self, i):
self.thisptr = new ConfigParams(<int> i)
def getPar1(self):
return self.thisptr.getPar1()
PySession class
# session.pxd
from configparams cimport *
cdef extern from "session.h":
cdef cppclass Session:
Session(ConfigParams parameters)
void doSomething()
# session.pyx
cdef class PySession:
cdef Session* thisptr
def __cinit__(self, pars):
# Note that here I have to extract the values
# from the pars (python PyConfigParams object)
# in order to build a c++ ConfigParams object
# which feeds the c ++ constructor of Session.
cdef ConfigParams* cpppargsptr = new ConfigParams(<int> pars.getPar1())
self.thisptr = new Session(cpppargsptr[0])
def doSomething(self):
self.thisptr.doSomething()
回答1:
Solution:
Forward declare PyConfigParams in the configparams.pxd module (so it can be invoked from the session.pyx module)
# configparams.pxd
cdef extern from "configparams.h":
cppclass ConfigParams:
ConfigParams(int par1)
int getPar1()
cdef class PyConfigParams:
cdef ConfigParams* thisptr
Import PyConfigParams in the session.pyx module, and cast the argument for the constuctor, this will grant access to the PyConfigParams pointer to the c++ object, which will need to be dereferenced.
# session.pyx
from configparams cimport PyConfigParams
from cython.operator cimport dereference as deref
cdef class PySession:
cdef Session* thisptr
def __cinit__(self, PyConfigParams pars):
self.thisptr = new Session(deref(pars.thisptr))
def doSomething(self):
self.thisptr.doSomething()
来源:https://stackoverflow.com/questions/10436837/cython-and-c-class-constructors