zoukankan      html  css  js  c++  java
  • 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.

  • 相关阅读:
    _DataStructure_C_Impl:图的邻接矩阵存储
    ios的单元測试OCUnit以及更新了之后的XCTestCase
    java之 ------ 可变參数和卫条件
    【能力提升】SQL Server常见问题介绍及高速解决建议
    NYOJ 116 士兵杀敌 (线段树,区间和)
    Spring和MyBatis环境整合
    TypeScript和JavaScript的一些小技巧记录
    VSCode配置TypeScript
    function 与 => 的区别
    Egret里用矢量挖圆形的洞
  • 原文地址:https://www.cnblogs.com/highkgao/p/4715252.html
Copyright © 2011-2022 走看看