2010-09-22 15 views
37

मैं उनकी बेहतर समझ प्राप्त करने के लिए सूची समझ के साथ खेल रहा था और मैं कुछ अप्रत्याशित आउटपुट में भाग गया जो मैं समझाने में सक्षम नहीं हूं। मुझे यह सवाल पहले नहीं पूछा गया है, लेकिन यदि यह दोहराया गया प्रश्न है, तो मैं क्षमा चाहता हूं।पायथन: उन्नत नेस्टेड सूची समझ सिंटेक्स

मैं अनिवार्य रूप से जेनरेटर उत्पन्न करने वाले जेनरेटर लिखने की कोशिश कर रहा था। एक साधारण जनरेटर सूची समझ का उपयोग करता है इस प्रकार दिखाई देगा:

(x for x in range(10) if x%2==0) # generates all even integers in range(10) 

मुझे क्या करना कोशिश कर रहा था एक जनरेटर है कि दो जनरेटर उत्पन्न लिखना था - की जो सीमा (10) में भी संख्या उत्पन्न पहले और दूसरे जिसमें से श्रेणी में विषम संख्या उत्पन्न हुई (10)। इस के लिए, मैंने किया था:

>>> (x for x in range(10) if x%2==i for i in range(2)) 
<generator object <genexpr> at 0x7f6b90948f00> 

>>> for i in g.next(): print i 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 1, in <genexpr> 
UnboundLocalError: local variable 'i' referenced before assignment 
>>> g.next() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
>>> g = (x for x in range(10) if x%2==i for i in range(2)) 
>>> g 
<generator object <genexpr> at 0x7f6b90969730> 
>>> g.next() 
Traceback (most recent call last): 
     File "<stdin>", line 1, in <module> 
     File "<stdin>", line 1, in <genexpr> 
    UnboundLocalError: local variable 'i' referenced before assignment 

मुझे समझ नहीं आता क्यों 'मैं' असाइनमेंट

मैंने सोचा कि यह i in range(2) के साथ कुछ हो सकता था से पहले संदर्भित किया जा रहा है, इसलिए मैंने किया:

>>> g = (x for x in range(10) if x%2==i for i in [0.1]) 
>>> g 
<generator object <genexpr> at 0x7f6b90948f00> 
>>> g.next() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 1, in <genexpr> 
UnboundLocalError: local variable 'i' referenced before assignment 

यह मुझे समझ में नहीं आया, इसलिए मैंने सोचा कि पहले कुछ आसान करने का सबसे अच्छा प्रयास है। इसलिए मैं सूचियों में वापस चला गया और करने की कोशिश की:

>>> [x for x in range(10) if x%2==i for i in range(2)] 
[1, 1, 3, 3, 5, 5, 7, 7, 9, 9] 

जो मैं के रूप में ही होने की उम्मीद:

>>> l = [] 
>>> for i in range(2): 
...  for x in range(10): 
...    if x%2==i: 
...      l.append(x) 
... 
>>> l 
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9] # so where is my list comprehension malformed? 

लेकिन जब मैं एक कूबड़ पर यह कोशिश की, इस काम किया:

>>> [[x for x in range(10) if x%2==i] for i in range(2)] 
[[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]] # so nested lists in nested list comprehension somehow affect the scope of if statements? :S 

तो मैंने सोचा कि यह समस्या हो सकती है कि if कथन किस स्तर का दायरा चलाता है। इसलिए मैंने यह कोशिश की:

>>> [x for x in range(10) for i in range(2) if x%2==i] 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

और अब मैं पूरी तरह उलझन में हूं। क्या कोई इस व्यवहार को समझा सकता है। मुझे समझ में नहीं आ रहा है कि मेरी सूची की समझ खराब क्यों प्रतीत होती है, और न ही मैं समझता हूं कि if कथन का दायरा कैसे काम करता है।

किसी भी मदद होगी बहुत सराहना

धन्यवाद

पुनश्च: एक ओर जहां सवाल सबूत पढ़ने, मुझे एहसास हुआ कि यह एक होमवर्क सवाल जैसे दिखते हैं करता है कि - ऐसा नहीं है।

+0

किया '[सीमा (10) में एक्स के लिए एक्स अगर एक्स% 2 == मैं रेंज में (2)] 'काम? मुझे 'NameError: name 'i' परिभाषित नहीं किया गया है '(पायथन 2.6.2) –

+0

@ManojGovindan: मुझे वही मिलता है जो आपको मिला (पायथन 2.6.5) – inspectorG4dget

+0

संबंधित: [पाइथन सूची समझ समझने के दायरे के बाद भी नाम रिबाइंड नाम । क्या यह सही है?] (Http://stackoverflow.com/q/4198906) –

उत्तर

33

आप कुछ कोष्ठक का उपयोग करने की आवश्यकता है:

((x for x in range(10) if x%2==i) for i in range(2)) 

This didn't make sense to me, so I thought it best to try something simpler first. So I went back to lists and tried:

[>>> [x for x in range(10) if x%2==i for i in range(2)] [1, 1, 3, 3, 5, 5, 7, 7, 9, 9]

यही काम किया क्योंकि पिछले एक सूची समझ संलग्न गुंजाइश के लिए मैं चर लीक, और वर्तमान एक के लिए मैं हो जाते हैं। ताजा पायथन दुभाषिया शुरू करने का प्रयास करें, और यह नाम त्रुटि के कारण विफल हो जाएगा। पाइथन 3 में काउंटर लीकिंग व्यवहार हटा दिया गया है।

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

के लिए पाश के लिए बराबर:

(x for x in range(10) if x%2==i for i in range(2)) 

होगा:

l = [] 
for x in range(10): 
    if x%2 == i: 
     for i in range(2): 
      l.append(x) 

जो भी एक नाम त्रुटि देता है।

EDIT2:

parenthesed संस्करण:

li = [] 
for i in range(2): 
    lx = [] 
    for x in range(10): 
     if x%2==i: 
      lx.append(x) 
    li.append(lx) 
+0

धन्यवाद, मैं रिसाव त्रुटि को समझता हूं, लेकिन ब्रांड्स की आवश्यकता क्यों है? बिना किसी कोष्ठक के कोड में अनुवाद (लूप के संदर्भ में) क्या होता है? मैं समझता हूं कि कोष्ठक समस्या को ठीक करते हैं, मुझे नहीं लगता कि – inspectorG4dget

+0

@ इंस्पेक्टर G4dget: मेरा अद्यतन उत्तर –

+0

देखें, इससे अब चीजें बहुत स्पष्ट हो जाती हैं, बहुत बहुत धन्यवाद। – inspectorG4dget

3

झूठ वाक्य सवाल का जवाब है:

((x for x in range(10) if x%2==i) for i in range(2)) 

के बराबर है। एक सुझाव: जनरेटर के शरीर में इतना सामान न लगाएं। एक समारोह बहुत अधिक पठनीय है।

def make_generator(modulus): 
    return (x for x in range(10) if x % 2 == modulus) 
g = (make_generator(i) for i in range(2)) 
+0

धन्यवाद। मैं इसे समझता हूं और मैं इसे पसंद करता हूं। लेकिन मैं सूची समझ के साथ कुछ अभ्यास करने की कोशिश कर रहा था और देख रहा हूं कि मैं उन्हें कितनी दूर धक्का दे सकता हूं – inspectorG4dget

6

झूठ रयान के जवाब पर थोड़ा विस्तार करना:

कुछ = (रेंज (10 में एक्स के लिए एक्स) अगर एक्स% 2 == मैं मैं रेंज में के लिए (2))

है बराबर करने के लिए:

def _gen1(): 
    def _gen2(): 
     for x in range(10): 
      if x%2 == i: 
       yield x 

    for i in range(2): 
     yield _gen2() 
something = _gen1() 
012:

def _gen1(): 
    for x in range(10): 
     if x%2 == i: 
      for i in range(2): 
       yield x 
something = _gen1() 

parenthesised संस्करण जबकि के बराबर है

यह वास्तव में दो जनरेटर उपज है:

[<generator object <genexpr> at 0x02A0A968>, <generator object <genexpr> at 0x02A0A990>] 

दुर्भाग्य से जनरेटर यह पैदावार कुछ हद तक अस्थिर रूप में उत्पादन आप उन्हें कैसे की खपत पर निर्भर करेगा कर रहे हैं:

>>> gens = ((x for x in range(10) if x%2==i) for i in range(2)) 
>>> for g in gens: 
     print(list(g)) 

[0, 2, 4, 6, 8] 
[1, 3, 5, 7, 9] 
>>> gens = ((x for x in range(10) if x%2==i) for i in range(2)) 
>>> for g in list(gens): 
     print(list(g)) 

[1, 3, 5, 7, 9] 
[1, 3, 5, 7, 9] 

मेरी सलाह जनरेटर लिखना है पूरी तरह से कार्य करता है: मुझे लगता है कि ऐसा करने के बिना i पर सही स्कोपिंग प्राप्त करने का प्रयास करना असंभव हो सकता है।

+1

यह क्यों है कि जनरेटर को 'सूची()' में लपेटना क्यों 0 से 0 पर शुरू होता है? (मैंने इसे अधिक जेनरेटर के साथ परीक्षण किया, ऐसा लगता है कि जनरेटर सभी एक ही काम कर रहे हैं) –

+0

जब जेनरेटर उपभोग करते हैं तो हमेशा वही काम करते हैं: वे आपको नंबर देते हैं जहां 'x% 2 == i'। पहला तरीका 'i' से' 0' सेट करता है, फिर भी जनरेटर उत्पन्न करता है जो कि संख्याओं को देने के लिए भी खपत होता है, फिर 'i' 1 बन जाता है और दूसरा जनरेटर लौटाता है जो आपको विषम संख्या देता है, एनबी। यह अलग-अलग मूल्यों के साथ हर बार 'i' वही था। 'सूची (जीन्स)' का अर्थ है कि दोनों जेनरेटर बनाए गए हैं ताकि जनरेटर का उपभोग करने से पहले 'i' को '1' पर सेट कर दिया गया हो। – Duncan

+0

ऐसा क्यों है कि 'i' पहले मामले में साझा नहीं किया गया है? –

5

झूठ रयान के लिए लूप बराबर मुझे निम्न में से प्रतीत होता है की ओर जाता है ठीक काम करने के लिए:

[x for i in range(2) for x in range(10) if i == x%2] 

आउटपुट

[0, 2, 4, 6, 8, 1, 3, 5, 7, 9] 
संबंधित मुद्दे