C-API: Pass a tuple to a method of a class

刘振海 1989lzhh at gmail.com
Tue Jan 10 08:24:40 EST 2012


Hi,
I have been using Cython for a period of time.
But I can not find a description for the "api" key word in Cython documents

cdef api float compute_norm(float init_value, float x, float y, float z):

Can you explain it a little bit? Thanks!

Regards,
Liu Zhenhai

2012/1/10 Stefan Behnel <stefan_ml at behnel.de>

> Hi again,
>
> just as a little teaser, to make it clear that I'm not joking, here's your
> code below translated into Cython.
>
> Stefan Behnel, 10.01.2012 13:33:
> > pasparis at noos.fr, 10.01.2012 11:57:
> >> the code is the following:
> > [...]
> >> // Class
> >> pclass = PyObject_GetAttrString(mymod, "cVector");
> >> if (pclass == NULL) {
> >> Py_DECREF(pclass);
> >> cout << "Can't find class\n";
> >> }
> >>
> >> // Parameters/Values
> >> args = Py_BuildValue("(f)", 100.0);
> >> if (args == NULL) {
> >> Py_DECREF(args);
> >> cout << "Can't build argument list for class instance\n";
> >> }
> >>
> >> // Object with parameter/value
> >> object = PyEval_CallObject(pclass, args);
> >> if (object == NULL) {
> >> Py_DECREF(object);
> >> cout << "Can't create object instance:\n";
> >> }
> >>
> >> // Decrement the argument counter as we'll be using this again
> >> Py_DECREF(args);
> >>
> >> // Get the object method - note we use the object as the object
> >> // from which we access the attribute by name, not the class
> >> method = PyObject_GetAttrString(object, "ComputeNorm");
> >> if (method == NULL) {
> >> Py_DECREF(method);
> >> cout << "Can't find method\n";
> >> }
> >>
> >> // Decrement the counter for our object, since we now just need
> >> // the method reference
> >> Py_DECREF(object);
> >>
> >> // Build our argument list - an empty tuple because there aren't
> >> // any arguments
> >>
> >> cout << "Prepare the Tuple:\n" ;
> >> // WE pass a tuple
> >> args = PyTuple_New( 3 );
> >> if (args == NULL) {
> >> Py_DECREF(args);
> >> cout << "Can't build argument list for method call\n";
> >> }
> >>
> >> PyObject *py_argument;
> >> // 1st argument
> >> py_argument = PyFloat_FromDouble(5.);
> >> PyTuple_SetItem(args, 0, py_argument);
> >>
> >> // 2nd argument
> >> py_argument = PyFloat_FromDouble(10.);
> >> PyTuple_SetItem(args, 1, py_argument);
> >>
> >> // 3nd argument
> >> py_argument = PyFloat_FromDouble(15.);
> >> PyTuple_SetItem(args, 2, py_argument);
> >>
> >> cout << "Before the Exec:\n" ;
> >> // Call our object method with arguments
> >> //ret = PyEval_CallObject(method,args);
> >> ret = PyObject_CallObject(method,args);
> >
> > Note that you are calling the method with three arguments here. It
> appears
> > that what you want is *one* argument instead, which happens to be a
> tuple.
> > So you need to wrap it in another tuple for calling. As I said, Cython
> will
> > do that for you.
>
> And here's the Cython code:
>
> """
> # in module "gluecode.pyx" (or whatever you want to name it)
>
> import mModule8
>
> cdef api float compute_norm(float init_value, float x, float y, float z):
>    vec = mModule8.cVector(init_value)
>    return vec.ComputeNorm( (x,y,z) )
> """
>
> At least, that's what I read from your C code above. I'm assuming here that
> your program is using C or C++, and that you want to embed a CPython
> runtime in it and be able to execute Python code through it. The above
> "compute_norm()" function is exported (as a C function) by the "gluecode"
> module which you can import in your C/C++ code (as you did already).
>
> Note also that the Cython code above is substantially more efficient than
> your implementation, because it uses faster type conversions and interned
> Python names for looking up the class and its method.
>
> Stefan
>
> --
> http://mail.python.org/mailman/listinfo/python-list
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20120110/819e9839/attachment-0001.html>


More information about the Python-list mailing list