2012-09-25 10 views
11

मैं साइथन का उपयोग किए बिना पाइथन सी-एक्सटेंशन लिख रहा हूं।सी सरणी को PyArray

मैं सी में एक डबल सरणी आवंटित करना चाहता हूं, इसे आंतरिक फ़ंक्शन में उपयोग करना चाहता हूं (जो कि फोरट्रान में होता है) और इसे वापस कर दें। मैं कहना है कि सी-फोरट्रान इंटरफ़ेस सी

static PyObject * 
Py_drecur(PyObject *self, PyObject *args) 
{ 
    // INPUT 
    int n; 
    int ipoly; 
    double al; 
    double be; 

    if (!PyArg_ParseTuple(args, "iidd", &n, &ipoly, &al, &be)) 
    return NULL; 

    // OUTPUT 
    int nd = 1; 
    npy_intp dims[] = {n}; 
    double a[n]; 
    double b[n]; 
    int ierr; 

    drecur_(n, ipoly, al, be, a, b, ierr); 

    // Create PyArray 
    PyObject* alpha = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, a); 
    PyObject* beta = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, b); 

    Py_INCREF(alpha); 
    Py_INCREF(beta); 

    return Py_BuildValue("OO", alpha, beta); 
} 

में पूरी तरह से काम करता है मैं इस कोड डिबग और जब मैं एक से बाहर अल्फा बनाने की कोशिश मैं एक विभाजन गलती मिलता है। वहां तक ​​सब कुछ ठीक काम करता है। फ़ंक्शन drecur_ काम करता है और अगर इसे हटा दिया जाता है तो मुझे वही समस्या मिलती है।

अब, सी डेटा के आसपास एक PyArray परिभाषित करने का मानक तरीका क्या है? मुझे प्रलेखन मिला लेकिन कोई अच्छा उदाहरण नहीं मिला। इसके अलावा, स्मृति रिसाव के बारे में क्या? क्या यह वापसी से पहले INCREF के लिए सही है ताकि अल्फा और बीटा का उदाहरण संरक्षित हो? जब उन्हें अब और आवश्यकता नहीं है तो deallocation के बारे में क्या?

संपादित मैं अंत में यह सही दृष्टिकोण NumPy cookbook में पाया के साथ मिल गया।

static PyObject * 
Py_drecur(PyObject *self, PyObject *args) 
{ 
    // INPUT 
    int n; 
    int ipoly; 
    double al; 
    double be; 
    double *a, *b; 
    PyArrayObject *alpha, *beta; 

    if (!PyArg_ParseTuple(args, "iidd", &n, &ipoly, &al, &be)) 
    return NULL; 

    // OUTPUT 
    int nd = 1; 
    int dims[2]; 
    dims[0] = n; 
    alpha = (PyArrayObject*) PyArray_FromDims(nd, dims, NPY_DOUBLE); 
    beta = (PyArrayObject*) PyArray_FromDims(nd, dims, NPY_DOUBLE); 
    a = pyvector_to_Carrayptrs(alpha); 
    b = pyvector_to_Carrayptrs(beta); 
    int ierr; 

    drecur_(n, ipoly, al, be, a, b, ierr); 

    return Py_BuildValue("OO", alpha, beta); 
} 

double *pyvector_to_Carrayptrs(PyArrayObject *arrayin) { 
    int n=arrayin->dimensions[0]; 
    return (double *) arrayin->data; /* pointer to arrayin data as double */ 
} 

इस पर टिप्पणी करने के लिए स्वतंत्र महसूस करें और उत्तर के लिए धन्यवाद।

उत्तर

1

एक समस्या यह हो सकती है कि आपके सरणी (ए, बी) को कम से कम तब तक चलाना होगा जब इसमें numpy-array शामिल है। आपने अपने दायरे को स्थानीय दायरे में बनाया है ताकि जब आप विधि छोड़ दें तो उन्हें नष्ट कर दिया जाएगा।

सरणी आवंटित पाइथन (उदाहरण के लिए PyArray_SimpleNew का उपयोग करके) की कोशिश करें, अपनी सामग्री को इसमें कॉपी करें और इसे एक पॉइंटर पास करें। यदि आप बूस्ट के खिलाफ बिल्डिंग एक विकल्प है, तो आप इन विवरणों का ख्याल रखने के लिए boost::python का उपयोग भी कर सकते हैं।

3

तो पहली चीजें जो संदिग्ध लगती हैं, यह है कि आपकी सरणी a और b फ़ंक्शन के स्थानीय दायरे में हैं। इसका मतलब है कि वापसी के बाद आपको एक अवैध स्मृति पहुंच मिल जाएगी।

तो तुम साथ

double *a = malloc(n*sizeof(double)); 

तो फिर तुम यह सुनिश्चित करें कि स्मृति बाद में वस्तु आपके द्वारा बनाए गए से मुक्त हो जाता है बनाने की जरूरत है सरणियों की घोषणा करनी चाहिए। दस्तावेज के इस उद्धरण देखें:

PyObject PyArray_SimpleNewFromData (पूर्णांक nd, मंद, पूर्णांक typenum, शून्य * डेटा npy_intp)

कभी कभी, आप एक ndarray में कहीं आबंटित स्मृति रैप करने के लिए चाहते हैं डाउनस्ट्रीम उपयोग के लिए वस्तु। यह दिनचर्या इसे करने के लिए सीधा बनाता है। पहले तीन तर्क PyArray_SimpleNew के समान हैं, अंतिम तर्क संगत स्मृति के एक ब्लॉक के लिए एक सूचक है जो ndarray को डेटा-बफर के रूप में उपयोग करना चाहिए जिसका सी-शैली संगत फैशन में व्याख्या किया जाएगा। एक ndarray के लिए एक नया संदर्भ वापस कर दिया गया है, लेकिन ndarray अपने डेटा का मालिक नहीं होगा। जब इस ndarray को हटा दिया जाता है, तो सूचक को मुक्त नहीं किया जाएगा।

आपको यह सुनिश्चित करना चाहिए कि लौटाई गई सरणी अस्तित्व में है, जबकि प्रदान की गई स्मृति मुक्त नहीं है। इसे संभालने का सबसे आसान तरीका यह है कि यदि डेटा किसी अन्य संदर्भ-गिनती पायथन ऑब्जेक्ट से आता है। पॉइंटर पारित होने के बाद इस ऑब्जेक्ट पर संदर्भ गणना बढ़ाई जानी चाहिए, और लौटे हुए ndarray के मूल सदस्य को पाइथन ऑब्जेक्ट को इंगित करना चाहिए जो डेटा का मालिक है।फिर, जब ndarray को हटा दिया जाता है, तो बेस-सदस्य उचित रूप से DECREF'd होगा। यदि आप चाहते हैं कि जैसे ही ndarray को हटा दिया गया हो, तो स्मृति को मुक्त कर दिया जाए, फिर वापस लौटे हुए ndarray पर OWNDATA ध्वज सेट करें।

अपने दूसरे प्रश्न Py_INCREF(alpha); के लिए यदि आप एक वैश्विक चर या एक वर्ग के सदस्य में संदर्भ रखने का इरादा आम तौर पर केवल आवश्यक है। लेकिन चूंकि आप केवल एक फ़ंक्शन लपेट रहे हैं, आपको इसे करने की ज़रूरत नहीं है। अफसोस की बात यह हो सकती है कि फ़ंक्शन PyArray_SimpleNewFromData संदर्भ काउंटर को 1 पर सेट नहीं करता है, अगर ऐसा होता है तो आपको इसे 1 तक बढ़ाना होगा। मुझे आशा है कि यह समझा जा सके;)।

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