C与python的调用二(简单参数传递、返回值获得)

上文简单介绍了python,以及在C中进行python模块的导入、函数、类接口的获得等比较基本的操作。接下来我们考虑:当我们已经获得了函数的接口之后,我们就应该能够对他进行调用了,接下来我们就来说一说函数的参数和返回值的问题。上文已经说了在python的世界里一切都是以PyObject为基类的,那么我们可以大胆的猜测,在python与C的函数接口中,入参和返回值都是PyObject*类型的。那么,问题就变成了如何将C中的简单类型转换成 PyObject*类型了,至此,我们应该去查查CPython的接口函数了。

       在CPython的接口函数中,可以作为python的函数调用方式有PyAPI_FUNC(PyObject *) PyEval_CallFunction(PyObject *obj, const char *format, ...),这个函数第一个参数就是函数的Python对象,后面就是参数列表,具体的该函数调用的时候有点类似于C的printf()函数。具体可以看个例子:

        PyObject *presult = PyEval_CallFunction(pFunc,"ss","5","5")

        在这行代码中,pFunc是函数的PyObject对象,“ss”对应的是const char *format,后面两个是具体的参数。对应printf的话,就是printf("%s%s","5',"5")。大致就是这么个意思,他这边的参数标识是没有%做修饰的,从这里可以看出来,s对应的就是字符串,具体的对应关系比较多,本文后面会附录所有的类型对应。

        现在,我们通过了PyEval_CallFunction调用了python的函数,获得了返回值,但是这个返回值是PyObject* 的,现在我们碰到的问题是,如何把这个对象转化成我们的需要的数据类型,这里Python给了一组相关的函数:

         PyAPI_FUNC(char *) PyString_AsString(PyObject *);

         PyAPI_FUNC(long) PyInt_AsLong(PyObject *);

         PyAPI_FUNC(unsigned long) PyInt_AsUnsignedLongMask(PyObject *);

         通过这些函数,我们就能够把这些Python对象转换成我们需要的数据类型了。

 

下面就用一个大数相加的例子,来展现python和C混合编程的魔力吧。

 

add.py:

def add(x,y,base,outbase):

    a = int(x,base) + int(y,base)

    if (outbase == 8):

        return str(oct(a))

    elif (outbase == 10):

        return str(a)

    elif (outbase == 16):

        return str(hex(a))

    else:

        return None

 

cpp:

#include "stdafx.h"

#include <Python.h>

 

 

int _tmain(int argc, _TCHAR* argv[])

{

  Py_Initialize();

  if ( !Py_IsInitialized() ) 

  { 

    return -1; 

  } 

  PyRun_SimpleString("import add"); 

  PyObject *pName,*pMoudle,*pDict,*pFunc;

  pName = PyString_FromString("add");

  pMoudle = PyImport_Import(pName);

  if (!pMoudle)

  {

    printf("get moudle handle error");

    return -1;

  }

  pDict = PyModule_GetDict(pMoudle); 

  if ( !pDict ) 

  { 

    printf("get moudledict handle error");

    return -1; 

  }

  pFunc = PyDict_GetItemString(pDict,"add"); 

  if ( !pFunc || !PyCallable_Check(pFunc) ) 

  { 

    printf("can't find function [add]"); 

    getchar(); 

    return -1; 

  } 

  PyObject *presult =     PyEval_CallFunction(pFunc,"ssii","12345678ABCDEF123456789","ABCDEF12345678ABCDEF12345678",16,10);

  char *pout = PyString_AsString(presult);

  printf(pout);

  system("pause");

  return 0;

}

各位见到了吧:在C中很复杂的大数相加,在python和C的混合编程下,是不是变得异常简单了呢,当然,大数相加可以这么算,所有的大数运算都可以这么实现,大家可以去尝试一下。

以后碰到一些在C中需要写很复杂的逻辑的,但是在python中能有很好的解决方案,大家都可以尝试去这么实现,相信会给你带来不一样的编程体验。

 

附录

类型的转换标识:

"s" (string or Unicode object) [char *]

Convert a Python string or Unicode object to a C pointer to a character string. You must not provide storage for the string itself; a pointer to an existing string is stored into the character pointer variable whose address you pass. The C string is null-terminated. The Python string must not contain embedded null bytes; if it does, a TypeError exception is raised. Unicode objects are converted to C strings using the default encoding. If this conversion fails, an UnicodeError is raised.

"s#" (string, Unicode or any read buffer compatible object) [char *, int]

This variant on "s" stores into two C variables, the first one a pointer to a character string, the second one its length. In this case the Python string may contain embedded null bytes. Unicode objects pass back a pointer to the default encoded string version of the object if such a conversion is possible. All other read buffer compatible objects pass back a reference to the raw internal data representation.

"z" (string or None) [char *]

Like "s", but the Python object may also be None, in which case the C pointer is set to NULL.

"z#" (string or None or any read buffer compatible object) [char *, int]

This is to "s#" as "z" is to "s".

"u" (Unicode object) [Py_UNICODE *]

Convert a Python Unicode object to a C pointer to a null-terminated buffer of 16-bit Unicode (UTF-16) data. As with "s", there is no need to provide storage for the Unicode data buffer; a pointer to the existing Unicode data is stored into the Py_UNICODE pointer variable whose address you pass.

"u#" (Unicode object) [Py_UNICODE *, int]

This variant on "u" stores into two C variables, the first one a pointer to a Unicode data buffer, the second one its length.

"es" (string, Unicode object or character buffer compatible object) [const char *encoding, char **buffer]

This variant on "s" is used for encoding Unicode and objects convertible to Unicode into a character buffer. It only works for encoded data without embedded NULL bytes.

The variant reads one C variable and stores into two C variables, the first one a pointer to an encoding name string (encoding), the second a pointer to a pointer to a character buffer (**buffer, the buffer used for storing the encoded data) and the third one a pointer to an integer (*buffer_length, the buffer length).

The encoding name must map to a registered codec. If set to NULL, the default encoding is used.

PyArg_ParseTuple() will allocate a buffer of the needed size using PyMem_NEW(), copy the encoded data into this buffer and adjust *buffer to reference the newly allocated storage. The caller is responsible for calling PyMem_Free() to free the allocated buffer after usage.

"es#" (string, Unicode object or character buffer compatible object) [const char *encoding, char **buffer, int *buffer_length]

This variant on "s#" is used for encoding Unicode and objects convertible to Unicode into a character buffer. It reads one C variable and stores into two C variables, the first one a pointer to an encoding name string (encoding), the second a pointer to a pointer to a character buffer (**buffer, the buffer used for storing the encoded data) and the third one a pointer to an integer (*buffer_length, the buffer length).

The encoding name must map to a registered codec. If set to NULL, the default encoding is used.

There are two modes of operation:

If *buffer points a NULL pointer, PyArg_ParseTuple() will allocate a buffer of the needed size using PyMem_NEW(), copy the encoded data into this buffer and adjust *buffer to reference the newly allocated storage. The caller is responsible for calling PyMem_Free() to free the allocated buffer after usage.

If *buffer points to a non-NULL pointer (an already allocated buffer), PyArg_ParseTuple() will use this location as buffer and interpret *buffer_length as buffer size. It will then copy the encoded data into the buffer and 0-terminate it. Buffer overflow is signalled with an exception.

In both cases, *buffer_length is set to the length of the encoded data without the trailing 0-byte.

"b" (integer) [char]

Convert a Python integer to a tiny int, stored in a C char.

"h" (integer) [short int]

Convert a Python integer to a C short int.

"i" (integer) [int]

Convert a Python integer to a plain C int.

"l" (integer) [long int]

Convert a Python integer to a C long int.

"c" (string of length 1) [char]

Convert a Python character, represented as a string of length 1, to a C char.

"f" (float) [float]

Convert a Python floating point number to a C float.

"d" (float) [double]

Convert a Python floating point number to a C double.

"D" (complex) [Py_complex]

Convert a Python complex number to a C Py_complex structure.

"O" (object) [PyObject *]

Store a Python object (without any conversion) in a C object pointer. The C program thus receives the actual object that was passed. The object's reference count is not increased. The pointer stored is not NULL.

"O!" (object) [typeobject, PyObject *]

Store a Python object in a C object pointer. This is similar to "O", but takes two C arguments: the first is the address of a Python type object, the second is the address of the C variable (of type PyObject *) into which the object pointer is stored. If the Python object does not have the required type, TypeError is raised.

"O&" (object) [converteranything]

Convert a Python object to a C variable through a converter function. This takes two arguments: the first is a function, the second is the address of a C variable (of arbitrary type), converted to void *. The converter function in turn is called as follows:

status = converter(objectaddress);

where object is the Python object to be converted and address is the void * argument that was passed to PyArg_ConvertTuple(). The returned status should be 1 for a successful conversion and 0 if the conversion has failed. When the conversion fails, the converter function should raise an exception.

"S" (string) [PyStringObject *]

Like "O" but requires that the Python object is a string object. Raises TypeError if the object is not a string object. The C variable may also be declared as PyObject *.

"U" (Unicode string) [PyUnicodeObject *]

Like "O" but requires that the Python object is a Unicode object. Raises TypeError if the object is not a Unicode object. The C variable may also be declared as PyObject *.

"t#" (read-only character buffer) [char *, int]

Like "s#", but accepts any object which implements the read-only buffer interface. The char * variable is set to point to the first byte of the buffer, and the int is set to the length of the buffer. Only single-segment buffer objects are accepted; TypeError is raised for all others.

"w" (read-write character buffer) [char *]

Similar to "s", but accepts any object which implements the read-write buffer interface. The caller must determine the length of the buffer by other means, or use "w#" instead. Only single-segment buffer objects are accepted; TypeError is raised for all others.

"w#" (read-write character buffer) [char *, int]

Like "s#", but accepts any object which implements the read-write buffer interface. The char * variable is set to point to the first byte of the buffer, and the int is set to the length of the buffer. Only single-segment buffer objects are accepted; TypeError is raised for all others.

"(items)" (tuple) [matching-items]

The object must be a Python sequence whose length is the number of format units in items. The C arguments must correspond to the individual format units in items. Format units for sequences may be nested.

Note: Prior to Python version 1.5.2, this format specifier only accepted a tuple containing the individual parameters, not an arbitrary sequence. Code which previously caused TypeError to be raised here may now proceed without an exception. This is not expected to be a problem for existing code.

It is possible to pass Python long integers where integers are requested; however no proper range checking is done -- the most significant bits are silently truncated when the receiving field is too small to receive the value (actually, the semantics are inherited from downcasts in C -- your mileage may vary).

A few other characters have a meaning in a format string. These may not occur inside nested parentheses. They are:

"|"

Indicates that the remaining arguments in the Python argument list are optional. The C variables corresponding to optional arguments should be initialized to their default value -- when an optional argument is not specified, PyArg_ParseTuple() does not touch the contents of the corresponding C variable(s).

":"

The list of format units ends here; the string after the colon is used as the function name in error messages (the ``associated value'' of the exception that PyArg_ParseTuple() raises).

";"

The list of format units ends here; the string after the colon is used as the error message instead of the default error message. Clearly, ":" and ";" mutually exclude each other.

原文地址:https://www.cnblogs.com/highkgao/p/4715252.html