2012-07-19 9 views
9

क्या कोई जनरेटर का उपयोग कर घोंसला वाले लूप के व्यवहार की व्याख्या करेगा? यहाँ एक उदाहरण है।जेनरेटर के साथ पाइथन नेस्टेड लूप काम नहीं करता है (कुछ मामलों में)?

a = (x for x in range(3)) 
b = (x for x in range(2)) 
for i in a: 
    for j in b: 
     print (i,j) 

बाहरी पाश किसी कारण से पहली यात्रा के बाद का मूल्यांकन नहीं किया गया है। नतीजा है,

(0, 0) 
(0, 1) 

दूसरी तरफ, अगर जनरेटर सीधे लूप में डाले जाते हैं, तो यह वही करता है जो मैं अपेक्षा करता हूं।

for i in (x for x in range(3)): 
    for j in (x for x in range(2)): 
     print (i,j) 

सभी 3x2 जोड़े दे रहा है।

(0, 0) 
(0, 1) 
(1, 0) 
(1, 1) 
(2, 0) 
(2, 1) 

उत्तर

22

यह क्योंकि b जनरेटर पाश के लिए बाहरी की पहली यात्रा के दौरान समाप्त हो रहा है है। इसके बाद के पुनरावृत्तियों में एक खाली आंतरिक लूप होगा (जैसे for x in()) तो अंदर क्या है कभी निष्पादित नहीं किया जाता है। यह झूठी छाप देता है कि यह बाहरी लूप है जो किसी भी तरह विफल रहता है।

आपका दूसरा उदाहरण काम करता है क्योंकि आंतरिक बाहरी जनरेटर प्रत्येक बाहरी पाश के लिए नया बना दिया जाता है। अपना पहला उदाहरण ठीक करने के लिए, आप एक ही करना है:

a = (x for x in range(3)) 
for i in a: 
    b = (x for x in range(2)) 
    for j in b: 
     print (i,j) 
+0

अहा में संकलित किया है! मैंने जनरेटर के थकावट को नहीं देखा। बहुत बहुत धन्यवाद। – phantomile

8

@lazyr इस शानदार ढंग से जवाब है, लेकिन मुझे लगता है कि यह जानने के लायक है जब नेस्टेड जनरेटर का उपयोग संदर्भ के लिए बाहर बिंदु होगा itertools.product के बारे में ...

for i, j in itertools.product(range(3), range(2)): 
    print (i, j) 

या (आप बहुत Vals की किया है):

for vals in itertools.product(range(45), range(12), range(3)): 
    print (sum(vals)) 

यह (IMHO) पठनीय और अत्यधिक खरोज बचा जाता है।

0

itertools.product इस उदाहरण के लिए सबसे अच्छा फिट है। लेकिन आप पुनरावृत्तियों के दौरान अधिक विकल्प चाहते हैं।

a = (range(2) for x in range(3)) 
for i in a: 
    for j in i: 
     print (i,j) 

इसके अलावा, मैं pytoolz कार्यात्मक सहायक पुस्तकालय से itertoolz.concat का उपयोग कारगर बनाने/इस तरह के मामलों समतल: यहाँ एक तरह से अभी भी उत्पाद विधि का उपयोग कर के बिना अपने उदाहरण में उत्पाद प्राप्त करने के लिए है। concat सिर्फ itertools.chain की तरह है, लेकिन बजाय एक ही तर्क जो iterators पैदावार कि सुलझाया हो लेता है:

from pytoolz import itertoolz 
a = (((x,y) for y in range(2)) for x in range(3)) 
for i,j in itertoolz.concat(a): 
    print (i,j) 

तो, ऊपर उत्पाद विधि की तुलना में कम पठनीय दिखता है, लेकिन/प्रत्येक पाश में छानने महीन सुक्ष्म परिवर्तनों के लिए अनुमति देता है स्तर। और निश्चित रूप से, आपके पास अंतिम पुनरावृत्ति तर्क के दौरान घोंसले के लिए घोंसला नहीं है जो अच्छा हो सकता है।

इसके अलावा, अगर आप का उपयोग pytoolz आप शायद का उपयोग करना चाहिए cytoolz, यह एक ही पुस्तकालय सी

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