2015-10-05 6 views
5

लटकने का कारण बनता है मैं पाइथन 2.x और 3.x में अंतर्निहित zip अनुकरण करने वाले 2 कार्यों के साथ प्रयोग कर रहा हूं। पहले एक सूची लौटाता है (पायथन 2.x के रूप में) और दूसरा एक एक जनरेटर समारोह जो एक समय में सेट उसके परिणाम में से एक टुकड़ा रिटर्न (अजगर 3.x के रूप में) है:जनरेटर अभिव्यक्ति का उपयोग करने से पाइथन

def myzip_2x(*seqs): 
    its = [iter(seq) for seq in seqs] 
    res = [] 
    while True: 
     try: 
      res.append(tuple([next(it) for it in its])) # Or use generator expression? 
      # res.append(tuple(next(it) for it in its)) 
     except StopIteration: 
      break 
    return res 

def myzip_3x(*seqs): 
    its = [iter(seq) for seq in seqs] 
    while True: 
     try: 
      yield tuple([next(it) for it in its])   # Or use generator expression? 
      # yield tuple(next(it) for it in its) 
     except StopIteration: 
      return 

print(myzip_2x('abc', 'xyz123'))     
print(list(myzip_3x([1, 2, 3, 4, 5], [7, 8, 9]))) 

यह अच्छी तरह से काम करता है और zip में निर्मित की उम्मीद उत्पादन देता है:

[('a', 'x'), ('b', 'y'), ('c', 'z')] 
[(1, 7), (2, 8), (3, 9)] 

तब मैं, अपने (लगभग) बराबर जनरेटर अभिव्यक्ति के साथ tuple() कॉल के अंतर्गत सूची समझ की जगह वर्ग कोष्ठक [] हटा कर के बारे में सोचा (क्यों जब जनरेटर को अस्थिर एक्सप के लिए ठीक होना चाहिए तो समझ का उपयोग करके एक अस्थायी सूची बनाएं tuple() द्वारा ected, सही?)

हालांकि, यह पाइथन को लटकने का कारण बनता है। यदि निष्पादन Ctrlसी (विंडोज़ पर आईडीईएल) का उपयोग करके समाप्त नहीं किया गया है, तो अंत में यह MemoryError अपवाद के साथ कई मिनटों के बाद बंद हो जाएगा।

कोड को डिबग करना (उदाहरण के लिए PyScripter का उपयोग करके) पता चला कि जेनरेटर अभिव्यक्ति का उपयोग होने पर StopIteration अपवाद कभी नहीं उठाया जाता है। myzip_2x() के लिए ऊपर पहला उदाहरण कॉल res को खाली tuples जोड़ने पर रहता है, जबकि myzip_3x() को दूसरे उदाहरण कॉल tuples (1, 7), (2, 8), (3, 9), (4,), (5,), (), (), (), ... अर्जित करता है।

क्या मुझे कुछ याद आ रही है?

और एक अंतिम ध्यान दें: एक ही फांसी व्यवहार प्रदर्शित होता है या its एक जनरेटर प्रत्येक समारोह (सूची comprehensions tuple() कॉल में उपयोग किया जाता है जब) की पहली पंक्ति में (its = (iter(seq) for seq in seqs) का प्रयोग करके) हो जाता है।

संपादित करें:

विवरण के लिए

धन्यवाद @Blckknght, तुम सही थे। This message ऊपर जेनरेटर फ़ंक्शन के समान उदाहरण का उपयोग करके क्या हो रहा है, इस बारे में अधिक जानकारी देता है। निष्कर्ष में, जनरेटर अभिव्यक्तियों का उपयोग करके, केवल पाइथन 3.5+ में काम करता है और इसे फ़ाइल के शीर्ष पर from __future__ import generator_stop कथन की आवश्यकता होती है और को RuntimeError के साथ बदलकर (फिर, सूची समझों के बजाय जनरेटर अभिव्यक्तियों का उपयोग करते समय) को बदलना पड़ता है।

संपादित करें 2:

ऊपर अंतिम नोट के लिए के रूप में: अगर its एक जनरेटर हो जाता है (its = (iter(seq) for seq in seqs) का प्रयोग करके) यह सिर्फ एक यात्रा का समर्थन करेंगे - क्योंकि जनरेटर एक शॉट iterators हैं। इसलिए यह पहली बार समाप्त हो गया है जबकि लूप चलाया जाता है और बाद के लूप पर केवल खाली ट्यूपल्स प्राप्त होते हैं।

उत्तर

2

जो व्यवहार आप देख रहे हैं वह एक बग है। यह इस तथ्य से उत्पन्न होता है कि एक जनरेटर से StopIteration अपवाद बुलबुला सामान्य रूप से बाहर निकलने वाले जनरेटर से अलग नहीं है। इसका मतलब है कि आप try और except के साथ जनरेटर पर एक लूप लपेट नहीं सकते हैं और लूप लॉक से बाहर निकलने के लिए StopIteration देखें, क्योंकि लूप तर्क अपवाद का उपभोग करेगा।

PEP 479 भाषा बदलने खलबली मचाने वाले पहले RuntimeError में ध्यान में न आया StopIteration एक जनरेटर बारी के अंदर बनाने के लिए द्वारा, जारी करने के लिए एक ठीक प्रस्ताव है। यह आपके कोड को काम करने की अनुमति देगा (आपके द्वारा प्राप्त अपवाद के प्रकार के लिए एक छोटे से ट्विक के साथ)।

पीईपी पाइथन 3.5 में लागू किया गया है, लेकिन पीछे की संगतता को संरक्षित करने के लिए, बदले गए व्यवहार केवल तभी उपलब्ध होते हैं जब आप अपनी फ़ाइलों के शीर्ष पर from __future__ import generator_stop डालकर अनुरोध करते हैं। नया व्यवहार डिफ़ॉल्ट रूप से पायथन 3.7 में सक्षम होगा (पायथन 3.6 पुराने व्यवहार के लिए डिफ़ॉल्ट होगा, लेकिन अगर स्थिति आती है तो यह चेतावनी जारी कर सकती है)।

0

जब आप ऐसा करेंगे:

tuple([next(it) for it in its]) 

आप पहली बार एक सूची बना रहे हैं, तो tuple() को इसे पारित। यदि सूची नहीं बनाई जा सकती है क्योंकि StopIteration उठाया गया है, तो सूची नहीं बनाई गई है और अपवाद प्रचारित है।

लेकिन जब आप कार्य करें:

tuple(next(it) for it in its) 

आप एक जनरेटर का निर्माण कर रहे हैं और tuple() को सीधे इसे पारित। ट्यूपल कन्स्ट्रक्टर जेनरेटर को इटरेटर के रूप में उपयोग करेगा: यानी, StopIteration तक आइटमों को देखेगा।

वह है, StopIterationtuple() द्वारा पकड़ा गया है, और प्रचारित नहीं है।

एक जेनरेटर जो तुरंत StopIteration उठाता है उसे खाली टुपल में परिवर्तित कर दिया जाता है।

0

मुझे इसके बारे में वास्तव में यकीन नहीं है, लेकिन ऐसा लगता है कि आपके पास नेस्टेड जनरेटर हैं और बाहरी एक को पकड़कर StopIteration पकड़ता है।

इस उदाहरण पर विचार:

def gen(its): 
    for it in its: 
     yield next(it) # raises StopIteration 

tuple(gen(its)) # doesn't raises StopIteration 

यह कुछ अपने संस्करण क्या करता है के बराबर होता है।

2

नीचे इन कोडों के रनटाइम व्यवहार के आधार पर अनुमान है, पायथन भाषा संदर्भ या संदर्भ कार्यान्वयन नहीं।

अभिव्यक्ति tuple(next(it) for it in its)tuple(generator) के बराबर है जहां generator = (next(it) for it in its) है। tuple निर्माता धारणात्मक नीचे कोड के बराबर है:

def __init__(self, generator): 
    for element in generator: 
     self.__internal_array.append(element) 

क्योंकि for बयान थकावट का संकेत है, जब जनरेटर StopIteration क्योंकि next(it) यह उठता है को जन्म देती है के रूप में किसी भी StopIteration पकड़ता, for बयान बस इसके शिकार हो सकते और सोचें कि जनरेटर समाप्त हो गया है। यही कारण है कि लूप कभी समाप्त नहीं होता है, और खाली tuples संलग्न हैं: अपवाद कभी भी tuple कन्स्ट्रक्टर को बुलबुला नहीं करता है।

सूची समझ, [next(it) for it in its], दूसरे हाथ पर, धारणात्मक बराबर

को
result = [] 
for it in its: 
    result.append(next(it)) 

तो StopIterationfor बयान से पकड़ा नहीं है।

यह उदाहरण शाब्दिक समझ और जेनरेटर अभिव्यक्ति के साथ कन्स्ट्रक्टर कॉल के बीच एक दिलचस्प नॉनट्रिविअल अंतर दिखाता है। ऐसा ही होगा यदि कोई list(next(it) for it in its बनाम [next(it) for it in its] का उपयोग करता है।

+0

मैं किसी भी लूप या फ़ंक्शन के बाहर कोड चलाकर अपने अनुमान की पुष्टि कर सकता हूं। –

+0

इस तरह के एक अच्छा वैचारिक स्पष्टीकरण के लिए धन्यवाद। – John

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