2012-04-05 15 views
5

सबसे पहले, मैं C++ शैली iterators उदाहरण quickly.for की समीक्षा:अधिक अभिव्यक्तिपूर्ण पायथन इटरेटर्स कैसे बनाएं? बस C++ इटरेटर तरह

//--- Iterating over vector with iterator. 
vector<int> v; 
. . . 
for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) { 
    cout << *it << endl; 
} 

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

पायथन की समस्याएं हैं: 1: वर्तमान में, पाश वाक्यविन्यास के लिए पायथन सी ++ के मुकाबले कम लचीला है। (अच्छी तरह से, सुरक्षित) 2: "it! = iter.end()" शैली की बजाय, पाइथन अपवाद फेंक देगा जब अगला() में और नहीं होगा। यह लचीला नहीं है।

प्रश्न 1: क्या मेरा विचार सही से ऊपर है?

ठीक है। यहां मेरा प्रश्न आता है, सी ++ इटरेटर के रूप में शक्तिशाली के रूप में अधिक शक्तिशाली पायथन इटरेटर को कैसे कार्यान्वित किया जाए? वर्तमान में, लूप सिंटैक्स के लिए पायथन सी ++ के मुकाबले कम लचीला है। मुझे कुछ संभावित समाधान भी मिलते हैं, जैसे http://www.velocityreviews.com/forums/t684406-pushback-iterator.html। लेकिन यह उपयोगकर्ता को यह पूछने के बजाय सामान को पुश_बैक करने के लिए कहता है -।

प्रश्न 2: पाइथन में बिडरेक्शनल इटरेटर को लागू करने के लिए सबसे अच्छा क्या है? बस http://www.cplusplus.com/reference/std/iterator/BidirectionalIterator/ की तरह।

it = v.begin(); 
while(it!=v.end()) { 
    //do sth here 

    if (condition1) 
     ++it;//suppose this iterator supports ++ 
    if(condition2) 
     --it;//suppose this iterator supports -- 
} 

मुख्य सुविधाएँ हैं:: 1) द्विदिश, 2) सरल "अंत" जाँच छद्म कोड निम्नलिखित है। "++" या "-" ऑपरेटर या सामान्य कार्य कोई फर्क नहीं पड़ता (इसके बावजूद इसमें कोई अर्थपूर्ण अंतर नहीं है)।

धन्यवाद,

अद्यतन: मैं जवाब से कुछ संभव समाधान मिल गया:

हे
i = 0 
while i < len(sequence): # or i < len and some_other_condition 
    star_it = sequence[i] 
    if condition_one(star_it): 
     i += 1 
    if condition_two(star_it): 
     i = max(i - 1, 0) 

हालांकि, सरणी के विपरीत, इस सूची के रैंडम एक्सेस होना चाहिए (एन)। मुझे लगता है कि आंतरिक रूप से पायथन में "सूची" ऑब्जेक्ट को सामान जैसी लिंक्ड-लिस्ट का उपयोग करके कार्यान्वित किया जाता है। इस प्रकार, यह जबकि लूप समाधान कुशल नहीं है। हालांकि, सी ++ में, हमारे पास "यादृच्छिक पुनरावर्तक", "बिडरेक्शनल इटरेटर" है। मुझे बेहतर समाधान कैसे प्राप्त करना चाहिए? धन्यवाद।

+1

क्या आप उस चीज़ का ठोस उदाहरण दे सकते हैं जो आप 'पायथन' में नहीं कर सकते हैं जिसे आप आसानी से 'सी ++' में कर सकते हैं? –

+0

पायथन 'उपज' + अपवाद तंत्र आश्चर्यजनक रूप से लचीला है (यह वही है जिसे हम कार्यात्मक प्रोग्रामिंग में "निरंतरता" कहते हैं)। उन्हें सही तरीके से उपयोग करना सीखें और आपको पुरस्कृत किया जाएगा। सी ++ की तुलना में पाइथन में कंपाउंड इटरेटर्स को परिभाषित करना बहुत आसान है। –

+0

यह प्रश्न बहुत अस्पष्ट है, और वर्तमान फॉर्म में प्रश्न का कोई वास्तविक जवाब नहीं है। –

उत्तर

0

असल में, सी ++ इटरेटर सिस्टम इतना अच्छा नहीं है। Iterators संकेत के लिए समान हैं, और वे उनके संकट है:

  • विलक्षण मान: v.end() सुरक्षित रूप से dereferenced नहीं किया जा सकता
  • उलट मुद्दों: std::for_each(end, begin, func);
  • बेमेल मुद्दों: std::for_each(v0.begin(), v2.end(), func);

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

Range की अवधारणा इतना सी ++ 11 से बेहतर है का परिचय रेंज के लिए पाश निर्माण:

for (Object& o: range) { 
} 

कोई भी चीज जो पुनरावर्तक के साथ संभव है एक सीमा के साथ भी हो सकता है, हालांकि यह लग सकता है कुछ बार इसे महसूस करने के लिए और कुछ अनुवाद पहले हम में से उन लोगों के लिए अतियथार्थवादियों को लगता है जो सी ++ सूचक-जैसे इटरेटर के साथ शिक्षित थे। उदाहरण के लिए, subranges पूरी तरह से व्यक्त किया जा सकता:

for (Object& o: slice(range, 2, 9)) { 
} 

जहां slicerange भीतर स्थिति [2, 9) में सभी तत्वों को ले जाएगा।

तो, अपनी भाषा (पायथन) से लड़ने के बजाय आपको इसमें आगे बढ़ना चाहिए और इसकी शैली को गले लगा देना चाहिए। एक भाषा के खिलाफ लड़ना आम तौर पर एक हारने वाली लड़ाई है, अपने मुहावरे सीखना, कुशल बनना।

+0

बस शब्दों में कहें, मुझे बस एक बिडरेक्शनल इटरेटर चाहिए। हो सकता है कि हमारे पास इतनी व्याकरण चीनी हो, यह आसान लगती है लेकिन सी ++ में बेवकूफ और पारदर्शी नहीं है। –

5

अधिकांश स्थितियों के लिए, पायथन का for और इटरेटर आसपास की सबसे सरल चीज हैं। यह उनका लक्ष्य है और उन्हें लचीलापन के लिए समझौता नहीं करना चाहिए - लचीलापन की उनकी कमी कोई समस्या नहीं है

कुछ स्थितियों के लिए जहां आप for लूप का उपयोग नहीं कर सके, सी ++ इटरेटर सरल हो सकते हैं। लेकिन पाइथन में ऐसा करने का हमेशा एक तरीका है जो सी ++ इटरेटर का उपयोग करने से अधिक जटिल नहीं है।


आप पाशन से इटरेटर को आगे बढ़ाने को अलग करने के लिए, बस एक while पाश का उपयोग की जरूरत है:

it = iter(obj) 

try: 
    while True: # or some secondary break condition other than StopIteration 
     star_it = next(it) 
     if condition_one(star_it): 
      star_it = next(it) 
except StopIteration: 
    pass # exhausted the iterator 

मैं कहाँ --it अजगर में समझ में आता है केवल दो स्थितियों के बारे में सोच सकते हैं।

पहला यह है कि आप एक अनुक्रम पर फिर से चल रहे हैं। उस मामले में, यदि आप पीछे की ओर जाने की जरूरत है, पुनरावर्तक बिल्कुल का उपयोग नहीं करते - बस एक while पाश के साथ एक काउंटर का उपयोग करें:

i = 0 
while i < len(sequence): # or i < len and some_other_condition 
    star_it = sequence[i] 
    if condition_one(star_it): 
     i += 1 
    if condition_two(star_it): 
     i = max(i - 1, 0) 

पीछे नहीं है आप एक दोगुना लिंक्ड सूची से अधिक पुनरावृत्ति कर रहे हैं । उस मामले में, फिर से, पुनरावर्तक का उपयोग नहीं है - बस सामान्य रूप से नोड्स पार:

current = node 
while current: # or any break condition 
    if condition_one(current): 
     current = current.next 
    if condition_two(star_it): 
     current = current.prev 

एक स्थिति है जहाँ आप सकता लगता है कि यह समझ में आता है, लेकिन आप ऊपर किसी भी विधि का उपयोग नहीं कर सकते , set या dict जैसे एक अनियंत्रित संग्रह के साथ है। हालांकि, --it उस मामले में समझ में नहीं आता है। चूंकि संग्रह अनियंत्रित है, अर्थात्, पहले से प्राप्त वस्तुओं में से कोई भी उपयुक्त होगा - न केवल वास्तविक पिछले आइटम।

तो, आदेश, या तो mydict.values() या tuple(myset) की तरह एक दृश्य से अधिक पुनरावृत्ति और एक काउंटर का उपयोग करके वापस करने के लिए, आप स्मृति की जरूरत है जाने के लिए सही वस्तु को पता है में, या पिछले मूल्यों का एक दृश्य संयोजन से आप जा सकते हैं और का उपयोग कर के रूप में लूप और nextfor लूप के बजाय उपरोक्त के रूप में।

+1

@XinlinCao लेकिन उन परिस्थितियों के अनुरूप समाधान सामान्य से अधिक उपयोग करना आसान है, खासकर जब सामान्य व्यक्ति को अन्य स्थितियों के लिए अधिक जटिल बनाना होगा। पाइथन में पार्सिंग के लिए उपकरण हैं। जहां तक ​​फाइलें हैं, मैं नहीं देखता कि 'तलाश' कहने से एक इटरेटर बेहतर कैसे है? – agf

+2

@XinlinCao: आपके उपयोग के मामले बहुत अस्पष्ट हैं। एक ठोस वास्तविक दुनिया के उपयोग-मामले दें, और हम आपको पायथन में एक अच्छा समाधान दिखा सकते हैं। –

+0

@XinlinCao हम आपको यह बताने की कोशिश कर रहे हैं कि __that गलत सवाल है। पाइथन में सी ++ में बिडरेक्शनल इटरेटर के साथ क्या करना है, इसके लिए बेहतर तरीके हैं। आपके समाधान के लिए – agf

0

आप C++ का एक समान तरीके से अजगर वस्तुओं का उपयोग कर लागू कर सकते हैं:

class Iterable(object): 
    class Iterator(object): 
    def __init__(self, father, pos=0): 
     self.father = father 
     self.pos = pos 

    def __getitem__(self, pos=0): 
     return self.father[self.pos + pos] 

    def __setitem__(self, pos, value): 
     self.father[self.pos + pos] = value 

    def __iadd__(self, increment): 
     self.pos += increment 
     return self 

    def __isub__(self, decrement): 
     self.pos -= decrement 
     return self 

    def __ne__(self, other): 
     return self.father != other.father or self.pos != other.pos 

    def __eq__(self, other): 
     return not (self != other) 

    def begin(self): 
    return self.Iterator(self) 

    def end(self): 
    return self.Iterator(self, len(self)) 

class Vector(list, Iterable): 
    pass 

v = Vector([54, 43, 32, 21]) 

counter = 0 
it = v.begin() 
print it, it[0] 
while it != v.end(): 
    counter += 1 
    print it[0] 
    if counter == 2: 
    it += 1; # suppose this iterator supports ++ 
    if counter == 1: 
    it -= 1; # suppose this iterator supports -- 
    it += 1 

यह बदलता है *itit[0] द्वारा it += 1 द्वारा और it++ (यह भी सी ++ के लिए एनालॉग), लेकिन प्रभाव में यह बहुत ज्यादा ही रहता है।

आप pythonic तरीके छोड़ अगर आप ऐसा करते हैं, हालांकि कुछ परिस्थितियों के लिए ;-)

1

समाधान आपका उल्लेख किया:

  1. आप अंतर्निहित कंटेनर में वस्तुओं बदलना चाहते हैं। शब्दकोशों के लिए, चाबी या अधिक आइटम को पुनरावृति न केवल मान:

    for key, value in my_dict.iteritems(): 
        if conditiion(value): 
         my_dict[key] = new_value 
    

    सूचियों के लिए enumerate() का उपयोग करें:

    for index, item in enumerate(my_list): 
        if condition(item): 
         my_list[index] = new_item 
    
  2. आप एक "देखो-आगे" मूल्य वाले पुनरावर्तक चाहते हैं। आप शायद एक विशिष्ट स्थिति के आधार पर कुछ प्रयोग करेंगे, लेकिन यहां एक सामान्य परिस्थितियों के लिए एक नुस्खा है:

    def iter_with look_ahead(iterable, sentinel=None): 
        iterable, it_ahead = itertools.tee(iterable) 
        next(it_ahead, None) 
        return izip_longest(iterable, it_ahead, fillvalue=sentinel) 
    
    for current, look_ahead in iter_with look_ahead(tokens): 
        # whatever 
    
  3. आप रिवर्स में पुनरावृति करना चाहते हैं। reversed() का उपयोग करने वाले कंटेनर के लिए इसका उपयोग करें।

  4. आप यादृच्छिक अभिगम चाहते हैं। बस सूची और उपयोग सूचकांकों में अपने iterable बारी:

    my_list = list(my_iterable) 
    
0

ध्यान दें कि अजगर में सूची वस्तु एक सरणी है, इसलिए दक्षता चिंता प्रश्न में आपका उल्लेख वास्तव में एक गैर मुद्दा है।

+1

यह समाधान के बजाय टिप्पणी खंड में होना चाहिए। – DaveyLaser

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