Я пытаюсь выяснить, как в модулях расширения 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]
