Sto cercando di capire come nei moduli di estensione C avere un numero variabile (e forse) piuttosto elevato di argomenti per una funzione.Modulo di estensione Python con numero variabile di argomenti
Leggere circa PyArg_ParseTuple sembra che tu debba sapere quanti da accettare, alcuni obbligatori e alcuni facoltativi ma tutti con una propria variabile. Speravo che PyArg_UnpackTuple fosse in grado di gestirlo ma sembra che mi dia solo errori di bus quando cerco di usarlo in quello che sembra essere il modo sbagliato.
Come esempio, prendi il seguente codice python che potresti voler creare in un modulo di estensione (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])))
Questo può essere chiamato con un numero qualsiasi di argomenti o di ripetuti su, hypot(3,4,5)
, hypot([3,4,5])
e hypot(*[3,4,5])
tutti danno la stessa risposta.
L'inizio della mia funzione C si presenta così
static PyObject *hypot_tb(PyObject *self, PyObject *args) {
// lots of code
// PyArg_ParseTuple or PyArg_UnpackTuple
}
Molti pensa a yasar11732. Qui per il prossimo ragazzo c'è un modulo di estensione completamente funzionante (_toolboxmodule.c) che accetta semplicemente qualsiasi argomento numerico o intero e restituisce una lista composta da quegli argomenti (con un nome povero). Un giocattolo ma illustra ciò che doveva essere fatto.
#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, allora è:
>>> import _toolbox
>>> _toolbox.hypot(*range(4, 10))
[4, 5, 6, 7, 8, 9]
Perché ci dite che state ottenendo gli arresti da/difficoltà con il '' PyArg_ * funzioni, e poi ci dimostrate tutto tranne come usi le funzioni 'PyArg_ *'? –
Dovresti mettere i tuoi ParseArguments all'interno di un'istruzione if per vedere se ci sono stati errori durante l'analisi (restituito null), e fare una pulizia e restituire null se ci sono stati errori. Altrimenti sopprimerai gli errori durante l'analisi degli argomenti. – yasar
Sì, sì hai ragione. Modifico il post –