Hi, today I fixed hopefully the remaining bugs in Python <-> C++ interface:
* Use the Python() C++ class as the only interface to Python * properly deallocated all memory when the Python() class is deleted * fixed numerous segfaults related to that * figured out how to pass your own (derived) C++ class to Python and get its virtual methods called properly from Python * figured out how to write the PY_NEW() function in Cython only, without the need of the stdcython.h/c files (that we currently have in hermes2d) * wrote test cases to all of the above (that could also serve as examples of usage, both in Python and in C++) The code is here: http://github.com/certik/hermes_common Here is a (complete) example how to use scipy to print the sparse matrices nicely (from C++): Python *p = new Python(); p->push("m", c2py_CSRMatrix(this)); p->exec("S = str(m.to_scipy_csr())"); printf("%s\n", py2c_str(p->pull("S"))); delete p; It initializes the wrappers/python (so the user doesn't have to worry about this at all --- this used to be quite nontrivial!), pushes the C++ matrix in (as a Python class, that's the "m" symbol), then converts it to scipy, calls str() on the scipy matrix (so scipy prints it), saves it to "S", then pulls the string "S" back to C++ and prints it using C++ printf(). Finally it frees the Python and the namespace (e.g. both "m" and "S" symbols will be freed). Notice that you don't have to worry about memory allocation, everything should just work. The py2c_* and c2py_* methods are conveniently defined in Cython, e.g.: cdef api char* py2c_str(object s): return s cdef api object c2py_CSRMatrix(c_CSRMatrix *m): cdef CSRMatrix c c = <CSRMatrix>PY_NEW(CSRMatrix) c.thisptr = <c_Matrix *>m return c and that's it, you don't have to redeclare it in C++, as Cython will do that for you automatically. If one changes these api functions, one has to run the convert_api.py script: http://github.com/certik/hermes_common/blob/master/convert_api.py that takes the standard Cython generated header file (that uses static/local API) and creates a new .h and .cpp files that use the global API, so that the user doesn't have to worry about this at all in C++. So all is automatic, and later on, after we use it more in hermes2d and hermes1d, and if all is ok, I'll see how cython could be modified, so that it can produce these files itself. It took me quite some time to figure everything out, but it's worthy. It used to be a big pain to use Python from C++ (for nontrivial things like the above, where you had to initialize python and the wrappers in each cpp file...), but with this Python() C++ class, everything is super easy now. Let's say you have this array (in practice way longer of course): double a[3] = {1., 5., 3.}; and you want to print it nicely for debugging purposes. Here is the complete code that you have to put in your program: Python p=Python(); p.push("A", c2numpy_double(a, 3)); p.exec("print A"); Which prints: [ 1. 5. 3.] Now compare this to the old way by hand: for (int i=0; i<3; i ++) printf("%f ", a[i]); printf("\n"); which prints: 1.000000 5.000000 3.000000 now imagine I want to just print the first 5, or last 5 numbers, or just taking advantage of the nice way numpy prints large matrices (it puts ... in the middle), then I can just use: p.exec("print 'Last two numbers:', A[-2:]"); etc. It is all pretty trivial now, but it seems noone has done this before, so it took me quite some time to figure everything out. So I am happy with the results, thanks Robert, Lisandro and others for the help. Ondrej _______________________________________________ Cython-dev mailing list [email protected] http://codespeak.net/mailman/listinfo/cython-dev
