2011-11-03 16 views
10

मैं यह समझने की कोशिश कर रहा हूं कि सी एक्सटेंशन मॉड्यूल में एक चर (और शायद) फ़ंक्शन में बड़ी संख्या में तर्क होने के लिए कैसे किया जाता है।तर्कों की परिवर्तनीय संख्या के साथ पायथन एक्सटेंशन मॉड्यूल

PyArg_ParseTuple के बारे में पढ़ना ऐसा लगता है कि आपको यह जानना है कि कितने स्वीकार करना है, कुछ अनिवार्य और कुछ वैकल्पिक लेकिन सभी अपने स्वयं के चर के साथ। मैं उम्मीद कर रहा था कि PyArg_UnpackTuple इसे संभालने में सक्षम होगा लेकिन ऐसा लगता है कि जब मैं गलत तरीके से प्रतीत होता हूं तो इसे बस कोशिश करता हूं और इसका उपयोग करता हूं।

उदाहरण के रूप में निम्न पायथन कोड लें जो कोई एक्सटेंशन मॉड्यूल (सी में) बनाना चाहता है।

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]) सभी एक ही जवाब दे।

मेरी सी समारोह की शुरुआत की तरह इस

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

अजगर में तो यह है:

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

आप हमें क्यों बताऊँ कि आप से दुर्घटनाओं हो रही * '' PyArg_ साथ कठिनाई हो रही कार्य /, और फिर हमें के अलावा सब कुछ दिखाने आप 'PyArg_ *' फ़ंक्शंस का उपयोग कैसे करते हैं? –

+0

आपको पार्सिंग (नल लौटाया गया) के दौरान त्रुटियों के दौरान त्रुटियों के दौरान त्रुटियों के दौरान त्रुटियों के दौरान त्रुटियों को वापस करने के लिए त्रुटियों के दौरान त्रुटियों के दौरान त्रुटियों को वापस करने के लिए त्रुटियों के अंदर एक पैरा कथन दर्ज करना चाहिए। अन्यथा आप तर्क पार्सिंग के दौरान त्रुटियों को दबाएंगे। – yasar

+0

हां, हाँ आप सही हैं। मैं पोस्ट संपादित करूंगा। –

उत्तर

8

मैं इस पहले की तरह कुछ का इस्तेमाल किया था। यह एक खराब कोड हो सकता है क्योंकि मैं अनुभवी सी कोडर नहीं हूं, लेकिन यह मेरे लिए काम करता है। विचार है, * तर्क सिर्फ एक पायथन ट्यूपल है, और आप कुछ भी कर सकते हैं जो आप पाइथन टुपल के साथ कर सकते हैं। आप 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; 
    } 
+2

"यह एक खराब कोड हो सकता है": कोड मुझे ठीक लग रहा है। –

+1

वाह, मुझे खुशी है कि मैंने पूछा; आप इसे किसी न किसी। थोड़ा tweaking और मेरी समस्या हल हो गई थी। मैं अपने प्रश्न को अगले व्यक्ति के लिए आपके पूरी तरह से काम कर रहे समाधान के साथ संपादित कर दूंगा। –

संबंधित मुद्दे