当前位置: 首页 > 面试题库 >

Python扩展模块具有可变数量的参数

姜泳
2023-03-14
问题内容

我试图弄清楚如何在C扩展模块中具有一个函数的变量(也许有很多)参数。

阅读有关PyArg_ParseTuple的内容,您似乎必须知道要接受多少,一些强制性的和一些可选的,但都具有自己的变量。我希望PyArg_UnpackTuple能够处理此问题,但是当我尝试以似乎错误的方式使用它时,它似乎只会给我总线错误。

举个例子,将以下可能要放入扩展模块中的python代码(用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])))

这可以用任何数量的参数调用或遍历,hypot(3,4,5)hypot([3,4,5]),并hypot(*[3,4,5])都给予了同样的答案。

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

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

许多人认为yasar11732。接下来的一个家伙是一个完全正常工作的扩展模块(_toolboxmodule.c),该模块只接受任何数字或整数参数,并返回由这些参数组成的列表(名称不正确)。一个玩具,但说明需要做什么。

#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");
}

在python中,则为:

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

问题答案:

我以前使用过这样的东西。因为我不是经验丰富的C程序员,所以代码可能很糟糕,但是对我有用。这个想法是,*
args只是一个Python元组,您可以执行Python元组可以做的任何事情。您可以检查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;
}

我正在这样调用此函数:

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;
    }


 类似资料:
  • 问题内容: 我想创建一个充当可执行文件的Docker映像,用户为其传递令牌作为环境变量。可执行文件具有用户应通过dockers CMD传递的子命令(认为git通过Env进行身份验证)。但是,Docker不会将CMD附加到入口点。我的Dockerfile的相关部分如下所示: 因此,如果执行此容器时没有任何CMD覆盖并且作为MY_TOKEN变量,我希望 被执行。如果用户使用覆盖启动容器,例如 我希望

  • 我想创建一个Docker映像,它充当一个可执行文件,用户将其作为环境变量传递一个令牌。该可执行文件包含用户应该通过dockers CMD传递的子命令(想想通过Env进行身份验证的git)。但是,Docker不会将CMD附加到入口点。我的Dockerfile的相关部分如下所示: 我希望 被处决。但是,如上所述,只有被执行,而CMD被忽略--无论我是在启动期间重写它还是在DockerFile中设置它。

  • ES6 的变量声明 ES6 中新增了 let 和 const 来定义变量: var:,ES5 和 ES6中,定义全局变量(是variable的简写)。 let:定义局部变量,替代 var。 const:定义常量(定义后,不可修改)。 var:全局变量 看下面的代码: { var a = 1; } console.log(a); //这里的 a,指的是

  • 问题内容: 我花了一些时间想知道是否有可能编写一个guice模块,该模块本身使用类型T进行参数化,并使用其type参数指定绑定。 像在此示例(不起作用)中那样: 我尝试了不同的方法,试图将T作为类/ TypeLiteral的实例传递给MyModule,但没有一个起作用。帮助表示赞赏。 问候,zukasz Osipiuk 问题答案: 为此,您将必须使用从头开始构建每个TypeLiteral 。您可以

  • 我在使用 blob 触发器的消费计划上创建了一个 Azure 函数。然后,我向 Blob 添加大量文件,并且我希望每次将文件添加到触发器时都会调用 Azure 函数。 因为我使用Azure函数和消耗计划,所以我希望不存在可伸缩性问题,对吗?错。 我可以轻松地将文件添加到blob中,速度比Azure函数处理它们的速度快。一百个用户可以添加到blob中,但在任何时候似乎只有一个Azure函数的实例在工

  • 我正在做一个Jenkins的工作,它接受来自用户的一些参数。我遇到了一个不希望的行为:在我的脚本有机会读取环境变量之前,Jenkins似乎在参数环境变量中扩展了环境变量引用。 如果用户输入 作为参数,我的脚本实际看到的是 的内容;环境变量已展开。如果输入的值包含 我的脚本只能看到一个 。但是,如果它包含环境中不存在,则该值将保持不变(不会引发任何类型的错误)。 这很不方便,因为它甚至出现在密码字段