Python扩展模块的参数变量数 [英] Python extension module with variable number of arguments

查看:115
本文介绍了Python扩展模块的参数变量数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出如何在C扩展模块有一个变量(也许)相当大量的参数的函数。

阅读有关 PyArg_ParseTuple 看来你得知道有多少接受,一些强制性和一些可选的,但都用自己的变量。我希望 PyArg_UnpackTuple 将能够处理这个问题,但它似乎只是给我总线错误,当我尝试和这似乎是错误的方式来使用它。

作为一个例子买那种可能希望成为一个扩展模块(在C)以下的蟒蛇code。

 高清hypot(*瓦尔斯):
    如果len(瓦尔斯)= 1!
        返回的Math.sqrt(Vals的总和((V ** 2 V)))
    其他:
        返回的Math.sqrt(总和((ⅴ** 2在瓦尔斯v [0])))

这可以被称为与任意数量的参数或迭代, hypot(3,4,5) hypot([3,4 5]) hypot(* [3,4,5])都给予相同的答案。

我的C函数的开始看起来像这样

 静态的PyObject * hypot_tb(*的PyObject自我,*的PyObject参数){
//很多code的
// PyArg_ParseTuple或PyArg_UnpackTuple
}


许多认为对 yasar11732 。这里未来的家伙是一个全功能的扩展模块(_toolboxmodule.c),仅仅发生在任何数量或整数参数,并返回由这些参数列表(一个贫穷的名称)。一个玩具,但说明了什么需要做。

 的#include< Python.h>诠释ParseArguments(长常用3 [],Py_ssize_t大小的PyObject *参数){
    / *从Py_Tuple取得正数的任意数量* /
    Py_ssize_t我;
    *的PyObject temp_p,* temp_p2;    对于(i = 0; I<大小;我++){
        temp_p = PyTuple_GetItem(参数,I);
        如果(temp_p == NULL){返回NULL;}        / *检查temp_p是数值* /
        如果(PyNumber_Check(temp_p)!= 1){
            PyErr_SetString(PyExc_TypeError,非数字的参数。);
            返回NULL;
        }        / *转换数到Python长,比C无符号长* /
        temp_p2 = PyNumber_Long(temp_p);
        改编[I] = PyLong_AsUnsignedLong(temp_p2);
        Py_DECREF(temp_p2);
    }
    返回1;
}静态的PyObject * hypot_tb(*的PyObject自我,*的PyObject参数)
{
    Py_ssize_t TupleSize = PyTuple_Size(参数);
    长* NUMS =的malloc(TupleSize * sizeof的(无符号长));
    *的PyObject list_out;
    INT I;    如果(!TupleSize){
        如果(!PyErr_Occurred())
            PyErr_SetString(PyExc_TypeError,你必须至少提供一个参数。);
        返回NULL;
    }
    如果(!(ParseArguments(NUMS,TupleSize,参数)){
        免费(NUMS);
        返回NULL;
    }    list_out = PyList_New(TupleSize);
    对于(i = 0; I< TupleSize;我++)
        PyList_SET_ITEM(list_out,我,PyInt_FromLong(NUMS [I]));
    免费(NUMS);
    返回(*的PyObject)list_out;
}静态PyMethodDef toolbox_methods [] = {
   {hypot(PyCFunction)hypot_tb,METH_VARARGS,
     添加文档这里\\ n},
    // NULL终止的Python看对象
     {NULL,NULL,0,NULL}
};PyMODINIT_FUNC init_toolbox(无效){
    Py_InitModule3(_工具箱,toolbox_methods,
                     工具箱模块);
}

在蟒蛇那么它是:

 >>>进口_toolbox
>>> _toolbox.hypot(*范围(4,10))
[4,5,6,7,8,9]


解决方案

我用了这样的事情早。这可能是一个坏code作为我不是一个有经验的C codeR,但它为我工作。我们的想法是,* ARGS仅仅是一个Python元组,你可以做任何事情,你可以用Python的元组做的。您可以检查 http://docs.python.org/c-api/tuple.html

  INT
ParseArguments(无符号长ARR [],Py_ssize_t大小的PyObject *参数){
    / *从Py_Tuple取得正数的任意数量* /
    Py_ssize_t我;
    *的PyObject temp_p,* temp_p2;
    对于(i = 0; I<大小;我++){
        temp_p = PyTuple_GetItem(参数,I);
        如果(temp_p == NULL){返回NULL;}        / *检查temp_p是数值* /
        如果(PyNumber_Check(temp_p)!= 1){
            PyErr_SetString(PyExc_TypeError,非数字的参数。);
            返回NULL;
        }        / *转换数到Python长,比C无符号长* /
        temp_p2 = PyNumber_Long(temp_p);
        改编[I] = PyLong_AsUnsignedLong(temp_p2);
        Py_DECREF(temp_p2);
        如果(ARR [I] == 0){
            PyErr_SetString(PyExc_ValueError,零不容许作为参数。);
            返回NULL;
        }
        如果(PyErr_Occurred()){返回NULL; }
    }    返回1;
}

我在调用这个函数是这样的:

 静态的PyObject *
function_name_was_here(*的PyObject自我,*的PyObject参数)
{
    Py_ssize_t TupleSize = PyTuple_Size(参数);
    Py_ssize_t我;
    结构bigcouples * TEMP =的malloc(sizeof的(结构bigcouples));
    无符号长电流;    如果(!TupleSize){
        如果(!PyErr_Occurred())
            PyErr_SetString(PyExc_TypeError,你必须至少提供一个参数。);
        免费(TEMP);
        返回NULL;
    }    无符号长* NUMS =的malloc(TupleSize * sizeof的(无符号长));    如果(!ParseArguments(NUMS,TupleSize,参数)){
        / *做一个清理,比返回NULL * /
        返回null;
    }

I am trying to figure out how in C extension modules to have a variable (and maybe) quite large number of arguments to a function.

Reading about PyArg_ParseTuple it seems you have to know how many to accept, some mandatory and some optional but all with their own variable. I was hoping PyArg_UnpackTuple would be able to handle this but it seems to just give me bus errors when I try and use it in what appears to be the wrong way.

As an example take the following python code that one might want to make into an extension module (in C).

def hypot(*vals):
    if len(vals) !=1 :
        return math.sqrt(sum((v ** 2 for v in vals)))
    else: 
        return math.sqrt(sum((v ** 2 for v in vals[0])))

This can be called with any number of arguments or iterated over, hypot(3,4,5), hypot([3,4,5]), and hypot(*[3,4,5]) all give the same answer.

The start of my C function looks like this

static PyObject *hypot_tb(PyObject *self, PyObject *args) {
// lots of code
// PyArg_ParseTuple or PyArg_UnpackTuple
}


Many thinks to yasar11732. Here for the next guy is a fully working extension module (_toolboxmodule.c) that simply takes in any number or integer arguments and returns a list made up of those arguments (with a poor name). A toy but illustrates what needed to be done.

#include <Python.h>

int ParseArguments(long arr[],Py_ssize_t size, PyObject *args) {
    /* Get arbitrary number of positive numbers from Py_Tuple */
    Py_ssize_t i;
    PyObject *temp_p, *temp_p2;

    for (i=0;i<size;i++) {
        temp_p = PyTuple_GetItem(args,i);
        if(temp_p == NULL) {return NULL;}

        /* Check if temp_p is numeric */
        if (PyNumber_Check(temp_p) != 1) {
            PyErr_SetString(PyExc_TypeError,"Non-numeric argument.");
            return NULL;
        }

        /* Convert number to python long and than C unsigned long */
        temp_p2 = PyNumber_Long(temp_p);
        arr[i] = PyLong_AsUnsignedLong(temp_p2);
        Py_DECREF(temp_p2);
    }
    return 1;
}

static PyObject *hypot_tb(PyObject *self, PyObject *args)
{
    Py_ssize_t TupleSize = PyTuple_Size(args);
    long *nums = malloc(TupleSize * sizeof(unsigned long));
    PyObject *list_out;
    int i;

    if(!TupleSize) {
        if(!PyErr_Occurred()) 
            PyErr_SetString(PyExc_TypeError,"You must supply at least one argument.");
        return NULL;
    }
    if (!(ParseArguments(nums, TupleSize, args)) { 
        free(nums);
        return NULL;
    }

    list_out = PyList_New(TupleSize);
    for(i=0;i<TupleSize;i++)
        PyList_SET_ITEM(list_out, i, PyInt_FromLong(nums[i]));
    free(nums);
    return (PyObject *)list_out;
}

static PyMethodDef toolbox_methods[] = {
   { "hypot", (PyCFunction)hypot_tb, METH_VARARGS,
     "Add docs here\n"},
    // NULL terminate Python looking at the object
     { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC init_toolbox(void) {
    Py_InitModule3("_toolbox", toolbox_methods,
                     "toolbox module");
}

In python then it is:

>>> import _toolbox
>>> _toolbox.hypot(*range(4, 10))
[4, 5, 6, 7, 8, 9]

解决方案

I had used something like this earlier. It could be a bad code as I am not an experienced C coder, but it worked for me. The idea is, *args is just a Python tuple, and you can do anything that you could do with a Python tuple. You can check http://docs.python.org/c-api/tuple.html .

int
ParseArguments(unsigned long arr[],Py_ssize_t size, PyObject *args) {
    /* Get arbitrary number of positive numbers from Py_Tuple */
    Py_ssize_t i;
    PyObject *temp_p, *temp_p2;


    for (i=0;i<size;i++) {
        temp_p = PyTuple_GetItem(args,i);
        if(temp_p == NULL) {return NULL;}

        /* Check if temp_p is numeric */
        if (PyNumber_Check(temp_p) != 1) {
            PyErr_SetString(PyExc_TypeError,"Non-numeric argument.");
            return NULL;
        }

        /* Convert number to python long and than C unsigned long */
        temp_p2 = PyNumber_Long(temp_p);
        arr[i] = PyLong_AsUnsignedLong(temp_p2);
        Py_DECREF(temp_p2);
        if (arr[i] == 0) {
            PyErr_SetString(PyExc_ValueError,"Zero doesn't allowed as argument.");
            return NULL;
        }
        if (PyErr_Occurred()) {return NULL; }
    }

    return 1;
}

I was calling this function like this:

static PyObject *
function_name_was_here(PyObject *self, PyObject *args)
{
    Py_ssize_t TupleSize = PyTuple_Size(args);
    Py_ssize_t i;
    struct bigcouples *temp = malloc(sizeof(struct bigcouples));
    unsigned long current;

    if(!TupleSize) {
        if(!PyErr_Occurred()) 
            PyErr_SetString(PyExc_TypeError,"You must supply at least one argument.");
        free(temp);
        return NULL;
    }

    unsigned long *nums = malloc(TupleSize * sizeof(unsigned long));

    if(!ParseArguments(nums, TupleSize, args)){
        /* Make a cleanup and than return null*/
        return null;
    }

这篇关于Python扩展模块的参数变量数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆