2012-06-26 8 views
10

मैं this question का उत्तर लिख रहा था जब मैंने देखा कि मेरे सरल कार्यान्वयन ने सही नतीजे नहीं दिए हैं।ज़िप() मेरे जेनरेटर के मान क्यों छोड़ता है?

In [1]: import itertools 
In [2]: gen = itertools.cycle((0,1,2)) 

In [3]: zip(gen, range(3)) 
Out[3]: [(0, 0), (1, 1), (2, 2)] 

In [4]: zip(gen, range(3)) 
Out[4]: [(1, 0), (2, 1), (0, 2)] 

जो भी कारण, gen के next() विधि कहा जाता है एक additioinal समय के लिए: एक ओर जहां नीचे बग शिकार, मैं निम्नलिखित देखा। इसे दर्शाने के लिए, मैं निम्नलिखित प्रयोग किया है:

class loudCycle(itertools.cycle): 
    def next(self): 
     n = super(loudCycle, self).next() 
     print n 
     return n 

In [6]: gen = loudCycle((0,1,2)) 
In [7]: zip(gen, range(3)) 
0 
1 
2 
0 
Out[7]: [(0, 0), (1, 1), (2, 2)] 

उत्तर

17

यह इसलिए होता है क्योंकि zip का मूल्यांकन करता है iterators from left to right, जिसका अर्थ है कि, तीन चरणों के बाद, यह कहता है next() पर gen और उसके बाद ही पर iter(range(3)) (या कुछ है कि तरह) और मुठभेड़ों एक StopIteration। इस के आसपास पाने के लिए, बाएं सबसे तर्क के रूप में उपयोग में कम (परिमित) iterable:

In [8]: zip(range(3), gen) 
0 
1 
2 
Out[8]: [(0, 0), (1, 1), (2, 2)] 
7

Your self-answer बिल्कुल सही है, और एक बहुत अच्छा समाधान प्रस्तुत करता है - अगरzip पर तर्कों में से एक हमेशा होता है दूसरे से छोटा हालांकि, ऐसी स्थितियों में जहां आप नहीं जानते कि कौन सा छोटा होगा, आपको islice उपयोगी मिल सकता है। islice यदि आप अपने जेनरेटर में पहली जेनरेटर से पहले आइटम चाहते हैं तो एक आसान कामकाज भी प्रदान करता है। आपके मामले में, आप ऐसा कर सकता है:

>>> import itertools 
>>> gen = itertools.cycle(('a', 'b', 'c')) 
>>> seq = range(3) 
>>> zip(itertools.islice(gen, len(seq)), seq) 
[('a', 0), ('b', 1), ('c', 2)] 
>>> zip(itertools.islice(gen, len(seq)), seq) 
[('a', 0), ('b', 1), ('c', 2)] 

आपका जवाब शायद इस मामले में बेहतर है - यह निश्चित रूप से आसान है - लेकिन मैंने सोचा कि मैं एक पूरक के रूप में जोड़ना चाहते हैं।

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