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.

时间: 2024-10-09 09:10:07

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

struts2在配置文件中调用Action的方法返回值

struts2在配置文件中可以调用Action的方法返回值 1.Action中 //文件下载名 public String getDownloadFileName(){ String downloadFileName = ""; String filename = fileName + ".xls"; try { downloadFileName = URLEncoder.encode(filename,"UTF-8"); } catch (Un

第三次博客作业package com.fry; //导入java.util.Arrays; import java.util.Arrays; public class Demo1 { public static void main(String[]args){ //创建对象,对象名为hello Demo1 hello =new Demo1(); //调用方法并将返回值保存在变量中

1.  某网站管理系统,用户注册时,电话号码为可选输入项,输入格式为:区号-电话号码—分机号,中间用“-”隔开.以下为jsp页面上的设计,且并未对输入做任何控制. 假设系统现在需要取出中间的电话号码部分,代码如下: /** * * 该方法根据用户输入取出中间的电话号码部分 * @param strPhoneNum 电话号码,如:“0591-83279988—002” * @return 返回号码部分,如:“83279988” */ public String getPhoneNumber(Str

Python学习笔记之函数作为返回值、闭包的解释

函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. 我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_sum(*args): ax = 0 for n in args: ax = ax + n return ax 但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数! def lazy_sum(*args): def sum(): ax = 0 for n in args:

&lt;Java&gt; 类 方法 参数传递 返回值类

类 用class关键字可以传建一个类. 类中可以设置两种类型的元素:字段(有时被称为数据成员),方法(有时被称为成员函数) 字段  字段即数据成员 字段可以是任何类型的对象(可以是是引用类型,也可以是基本类型) (3) 每个对象都有用来存储其字段的空间,普通字段是不可以在对象间共享的 两个对象都各自有他们自己的字段,虽然字段是同名的,但是这两个对象对这个字段的操作都是对自己的字段的操作,不能操作另一个对象的. 但是static修饰的字段,是在对象内共享的,他只有一份空间,不管是那个对象,对这个字

python限定方法参数类型、返回值类型、变量类型等

typing模块的作用 自python3.5开始,PEP484为python引入了类型注解(type hints) 类型检查,防止运行时出现参数和返回值类型.变量类型不符合. 作为开发文档附加说明,方便使用者调用时传入和返回参数类型. 该模块加入后并不会影响程序的运行,不会报正式的错误,只有提醒pycharm目前支持typing检查,参数类型错误会黄色提示 常用类型 int,long,float: 整型,长整形,浮点型 bool,str: 布尔型,字符串类型 List, Tuple, Dict,

调用父类方法和返回值

今天用面向对象写了一段代码,用创建的类重构父类的方法,实现函数锁能实现的功能:代码如下 1 from os import getpid 2 from time import sleep 3 from multiprocessing import Process 4 5 6 class MyProcess(Process): 7 8 def __init__(self, args): 9 super(MyProcess, self).__init__() 10 self.args = args 1

Android基础——调用Activity并获得返回值

图像选择:Main中点击选择图像按钮,启动Head活动用来选择图像, 然后将被选择图像通过bundle发送给Main,同时附带返回值,方便Main来判断 Head布局文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="

Struct2_使用Ajax调用Action方法并返回值

一.Login.jsp 1.<head>引入jquery: <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.js"></script> 2.界面控件: 用户名: <input type="text" id="userName"> <input typ

Python装饰器去装饰含返回值的函数

#!/usr/bin/evn python #_*_ coding:utf-8 -*- import socket def auth(func):     def inner(*args, **kwargs):             print 'befor'             temp = func(*args,**kwargs)             print 'after'             return temp     return inner @auth def c