Extended Python module series (3) ---- Parameter Parsing and result encapsulation, python ----
In the previous section, we introduced the overall process of extending the Python built-in modules in C language through a simple example. Starting from this section, we will discuss some details in depth, in the detailed discussion, [reference count] is involved from the beginning. First, we will discuss the Parameter Parsing of Python functions encapsulated in C language and the encapsulation returned by function results.
Parameter Parsing
The most common interface is
int PyArg_ParseTuple(PyObject *arg, char *format, ...);
Arg is a tuple object, which is passed to the C function from python. The format parameter must be a string. Generally, each character represents a type; the remaining parameters are the addresses of the variables corresponding to the format. The return value is an integer, 1 is returned for successful parsing, and 0 is returned for parsing errors.
The Python Object parameter received by the function is borrowed reference, so you do not need to increase the reference count.
Example:
Int OK; int I, j; long k, l; const char * s; int size; OK = PyArg_ParseTuple (args ,""); /* No parameter * // * Python call: f ()*/
OK = PyArg_ParseTuple (args, "s", & s);/* the parameter is a string * // * Possible Python call: f ('whoops! ')*/
OK = PyArg_ParseTuple (args, "lls", & k, & l, & s);/* the parameters are two long integers and one string * // * Possible Python call: f (1, 2, 'three ')*/
{Const char * file; const char * mode = "r"; int bufsize = 0; OK = PyArg_ParseTuple (args, "s | si", & file, & mode, & bufsize);/* The parameter must have at least one character string. It can have another character string or integer * // * Possible Python cballs: f ('spam') f ('spam ', 'W') f ('spam', 'wb', 100000 )*/}
{Int left, top, right, bottom, h, v; OK = PyArg_ParseTuple (args, "(ii)", & left, & top, & right, & bottom, & h, & v);/* the parameter is two tuples. The first tuple has two elements, each tuple is composed of two integers * // * Possible Python call: f (0, 0), (400,300), (10, 10 ))*/}
PyObject * p; OK = PyArg_ParseTuple (args, "O", & p);/* the parameter is a PyObject object that can represent any type in Python */
/* Possible Python call: f (1, 2 ))*/
The common format strings provided in Python C APIs are as follows (not all are listed, and others can be found in Python2.7 ):
S => const char *, convert the Python string to the character pointer; s # => const cahr *, Py_ssize_t, convert the Python string to the character pointer and the character length; B ==> unsigned char. convert a non-negative Python integer to C unsigned char; B ==> unsigned char; convert a Python integer to C unsigned char; h ==> short inH ==> unsigned short inti ==> intI ==> unsigned intl ==> long intk ==> unsigned longL ==> PY_LONG_LONG, convert a Python integer to a long value of C, which may not be supported by some platforms; K => unsigned py_long_logrowth => float: convert a Python floating point number to a float of C. Pyhton only has the double type, so the precision is lost here. D => double: Convert the Python floating point number to the double value of C. There is no loss of precision. O => PyObject *: Save the Python object in PyObject, here, the object reference count will not increase; (items) ==> tuple/* Other characters */| the following parameters are optional. The default values of default parameters must be provided in PyArg_ParseTuple ;: the string parameter list is at: end, followed by a description of the function; followed by an error description to replace the default error message.
Static PyObject * distance (PyObject * self, PyObject * args) {double x0, y0, z0, x1, y1, z1; if (! PyArg_ParseTuple (args, "(ddd)", & x0, & y0, & z0, & x1, & y1, & z1 )) /* accept two tuple parameters */{return NULL;} return PyFloat_FromDouble (sqrt (x0-x1) * (x0-x1) + (y0-y1) * (y0-y1) + (z0-z1) * (z0-z1 )));}
Result returned
Which corresponds to the parameter parsing function PyArg_ParseTuple is:
PyObject *Py_BuildValue(char *format, ...);
Format also specifies the type of each parameter in each parameter list, but the parameter passed to this function cannot be a pointer. Here, PyArg_ParseTuple is different and only the value is passed. Another important difference is that Py_BuildValue returns PyObject * and the reference count is automatically 1. If a PyObject * parameter is passed to the function, for example, the following code, in this case, the reference parameter of p will be increamented by one.
PyObject* p = PyFloat_FromDouble(1.0);Py_BuildValue('O', p);
In Python source code: Py_BuildValue will call static PyObject * do_mkvalue (const char ** p_format, va_list * p_va, int flags). Here the 'O' processing is as follows:
Case 'N': case's ': case 'O': if (** p_format =' & ') {typedef PyObject * (* converter) (void *); converter func = va_arg (* p_va, converter); void * arg = va_arg (* p_va, void *); ++ * p_format; return (* func) (arg );} else {PyObject * v; v = va_arg (* p_va, PyObject *); if (v! = NULL) {if (* p_format-1 )! = 'N') Py_INCREF (v);/* If the format is not 'n', the reference count is increased by 1. If the format is 'n ', reference count unchanged */} else if (! PyErr_Occurred ()/* If a NULL was passed * because a call that shoshould * have constructed a value * failed, that's OK, and we * pass the error on; but if * no error occurred it's not * clear that the caller knew * what she was doing. */PyErr_SetString (PyExc_SystemError, "NULL object passed to Py_BuildValue"); return v ;}
Example:
The left side is the function call form, and the right side is the returned Python value:
Py_BuildValue("") NonePy_BuildValue("i", 123) 123Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)Py_BuildValue("s", "hello") 'hello'Py_BuildValue("ss", "hello", "world") ('hello', 'world')Py_BuildValue("s#", "hello", 4) 'hell'Py_BuildValue("()") ()Py_BuildValue("(i)", 123) (123,)Py_BuildValue("(ii)", 123, 456) (123, 456)Py_BuildValue("(i,i)", 123, 456) (123, 456)Py_BuildValue("[i,i]", 123, 456) [123, 456]Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456}Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))
In addition to using the Py_BuildValue function to return Python objects, you can also call the encapsulated functions provided by each type. For example, in our previous test module, the distance function needs to return a Python float object, you can call the PyFloat_FromDouble provided by floatobject:
PyObject * PyFloat_FromDouble (double fval) {register PyFloatObject * op; if (free_list = NULL) {if (free_list = fill_free_list () = NULL) return NULL ;} /* Inline PyObject_New */op = free_list; free_list = (PyFloatObject *) Py_TYPE (op); (void) PyObject_INIT (op, & PyFloat_Type ); /* initialize reference count */op-> ob_fval = fval; return (PyObject *) op ;}