को सरल समाधान:
PyErr_SetString(PyExc_StopIteration,"End of list");
return NULL;
यहाँ इस मुद्दे पर आगे पढ़ने के लिए एक और महान जवाब है:
अपने समारोह में
इसलिए, जब आप सरणी के अंत तक पहुँचते हैं, तो आप सिर्फ इस की जरूरत है यह __getitem__
को लागू करना है और एक अवैध अनुक्रमणिका के लिए IndexError
अपवाद फेंकना है।
मैं एक साथ इस का एक उदाहरण रखा, __getitem__
को लागू करने और क्रमश: एक अपवाद को बढ़ाने के लिए %extend
और बड़ा घूँट में %exception
का उपयोग कर:
static MyStruct *test() {
static MyStruct inst = {0,0};
if (!inst.clientdata) {
inst.len = 10;
inst.clientdata = malloc(sizeof(double)*inst.len);
for (size_t i = 0; i < inst.len; ++i) {
inst.clientdata[i] = i;
}
}
return &inst;
}
: मैं test.h को जोड़कर यह परीक्षण किया
%module test
%include "exception.i"
%{
#include <assert.h>
#include "test.h"
static int myErr = 0; // flag to save error state
%}
%exception MyStruct::__getitem__ {
assert(!myErr);
$action
if (myErr) {
myErr = 0; // clear flag for next time
// You could also check the value in $result, but it's a PyObject here
SWIG_exception(SWIG_IndexError, "Index out of bounds");
}
}
%include "test.h"
%extend MyStruct {
double __getitem__(size_t i) {
if (i >= $self->len) {
myErr = 1;
return 0;
}
return $self->clientdata[i];
}
}
और निम्न पायथन चला रहा है:
import test
for i in test.test():
print i
कौन सा प्रिंट:
python run.py
0.0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
और फिर समाप्त होता है।
एक वैकल्पिक दृष्टिकोण एक typemap का उपयोग कर एक PyList
सीधे MyStruct
मैप करने के लिए भी संभव है:
%module test
%{
#include "test.h"
%}
%typemap(out) (MyStruct *) {
PyObject *list = PyList_New($1->len);
for (size_t i = 0; i < $1->len; ++i) {
PyList_SetItem(list, i, PyFloat_FromDouble($1->clientdata[i]));
}
$result = list;
}
%include "test.h"
यह किसी भी समारोह है कि एक MyStruct *
रिटर्न से वापसी मान वाला PyList
पैदा करेगा। मैंने पिछली विधि के समान कार्य के साथ इस %typemap(out)
का परीक्षण किया।
तुम भी एक इसी %typemap(in)
और %typemap(freearg)
रिवर्स के लिए, इस अपरीक्षित कोड की तरह कुछ लिख सकते हैं: पुनरावर्तक का उपयोग जुड़ा हुआ सूचियों की तरह कंटेनरों के लिए और अधिक समझ बनाने हैं
%typemap(in) (MyStruct *) {
if (!PyList_Check($input)) {
SWIG_exception(SWIG_TypeError, "Expecting a PyList");
return NULL;
}
MyStruct *tmp = malloc(sizeof(MyStruct));
tmp->len = PyList_Size($input);
tmp->clientdata = malloc(sizeof(double) * tmp->len);
for (size_t i = 0; i < tmp->len; ++i) {
tmp->clientdata[i] = PyFloat_AsDouble(PyList_GetItem($input, i));
if (PyErr_Occured()) {
free(tmp->clientdata);
free(tmp);
SWIG_exception(SWIG_TypeError, "Expecting a double");
return NULL;
}
}
$1 = tmp;
}
%typemap(freearg) (MyStruct *) {
free($1->clientdata);
free($1);
}
, लेकिन पूर्णता के लिए यहां MyStruct
__iter__
के साथ ऐसा करने के बारे में आप कैसे जा सकते हैं। मुख्य बात यह है कि आपको __iter__()
और next()
की आवश्यकता होती है, जो MyStructIter
को %inline
का उपयोग करके एक ही समय में परिभाषित और लपेटा जाता है क्योंकि यह सामान्य सी एपीआई का हिस्सा नहीं है:
%module test
%include "exception.i"
%{
#include <assert.h>
#include "test.h"
static int myErr = 0;
%}
%exception MyStructIter::next {
assert(!myErr);
$action
if (myErr) {
myErr = 0; // clear flag for next time
PyErr_SetString(PyExc_StopIteration, "End of iterator");
return NULL;
}
}
%inline %{
struct MyStructIter {
double *ptr;
size_t len;
};
%}
%include "test.h"
%extend MyStructIter {
struct MyStructIter *__iter__() {
return $self;
}
double next() {
if ($self->len--) {
return *$self->ptr++;
}
myErr = 1;
return 0;
}
}
%extend MyStruct {
struct MyStructIter __iter__() {
struct MyStructIter ret = { $self->clientdata, $self->len };
return ret;
}
}
iteration over containers के लिए आवश्यकताओं को ऐसी है कि कंटेनर __iter__()
को लागू करने और एक नया इटरेटर वापस जाने के लिए की जरूरत है कर रहे हैं, लेकिन next()
जो अगले आइटम वापस आती है और इटरेटर इटरेटर खुद भी एक __iter__()
विधि की आपूर्ति करनी होगी वृद्धि कर देता है के अलावा। इसका मतलब है कि कंटेनर या इटरेटर को समान रूप से इस्तेमाल किया जा सकता है।
MyStructIter
को पुनरावृत्ति की वर्तमान स्थिति का ट्रैक रखने की आवश्यकता है - जहां हम हैं और हमने कितना छोड़ा है। इस उदाहरण में मैंने अगले आइटम पर एक पॉइंटर रखकर और एक काउंटर जिसे हम अंत में मारते समय बताने के लिए उपयोग करते थे। (
%inline %{
struct MyStructIter {
MyStruct *list;
size_t pos;
};
%}
%include "test.h"
%extend MyStructIter {
struct MyStructIter *__iter__() {
return $self;
}
double next() {
if ($self->pos < $self->list->len) {
return $self->list->clientdata[$self->pos++];
}
myErr = 1;
return 0;
}
}
%extend MyStruct {
struct MyStructIter __iter__() {
struct MyStructIter ret = { $self, 0 };
return ret;
}
}
इस उदाहरण में हम वास्तव में सिर्फ इस्तेमाल किया जा सकता था: तुम भी तरह MyStruct
iterator उपयोग कर रहा है के लिए एक सूचक है और उस के भीतर की स्थिति के लिए एक काउंटर, कुछ रखकर sate पर नज़र रखी जा सकता था __iter__()
की आपूर्ति करके प्रति और पहले प्रकार के समान next()
की प्रतिलिपि बनाकर इसे एक पुनरावर्तक के रूप में कंटेनर के रूप में।मैं क्या किया नहीं है कि मेरी मूल जवाब में क्योंकि मैंने सोचा की तुलना में दो भिन्न प्रकार की है कि कम स्पष्ट हो सकता है - एक कंटेनर और कहा कि कंटेनर के लिए एक इटरेटर)
स्निपेट के लिए धन्यवाद। त्वरित सवाल, क्या आपने पाइथन अंत से इसका परीक्षण किया? मैं टाइपमैप और पायलिस्ट/पायटुपल के बारे में बहुत कुछ नहीं जानता लेकिन मुझे संदेह है कि वे जो कुछ मैं प्राप्त करना चाहता हूं उसके करीब हैं (यानी सी स्ट्रक्चर को पायथन अनुक्रम प्रकार के रूप में देखें)। मुख्य बिंदु हालांकि, यह है कि मेरी मुख्य समस्या यह है कि मैं सी संरचना में तत्वों को पुन: सक्रिय करने में सक्षम नहीं हूं। शायद सी स्ट्रक्चर को सूची या टुपल के रूप में उजागर करने में दो पक्षियों (पुनरावृत्ति और सरणी सीमाओं की जांच) को मारने में मदद मिलती है। वे दो समस्याएं हैं जिन्हें मैं हल करने की कोशिश कर रहा हूं - क्या टाइपमैप + पिलिस्ट आगे बढ़ रहा है? तुम क्या सोचते हो? –
@ होमुनकुलस रेटिकुली - मैंने दिखाए गए 'टेस्ट()' फ़ंक्शन का उपयोग करके पाइथन पक्ष से सब कुछ परीक्षण किया, हालांकि टाइपमैप के लिए मैंने केवल '% टाइपमैप (आउट) 'का परीक्षण किया, लेकिन दोनों विधियों ने' के लिए ' में ... पायथन निर्माण। – Flexo
@ होमुनकुलस रेटिकुली - मैंने अपने उत्तर में '__iter __()' संस्करण भी जोड़ा है, हालांकि मैं इस उदाहरण में '__getitem __()' संस्करण को अधिक पसंद करता हूं। उपयोगी स्निपेट और विस्तृत स्पष्टीकरण के लिए अब तक – Flexo