वास्तव में एक जनरेटर समझ कैसे काम करता है?


91

जनरेटर की समझ क्या करती है? यह कैसे काम करता है? मुझे इसके बारे में कोई ट्यूटोरियल नहीं मिला।


1
स्पष्ट होने के लिए, इन के लिए भाषा का नाम जनरेटर की अभिव्यक्ति है , न कि जनरेटर की समझ
शैडो रेंजर

1
@ShadowRanger जुलाई में 2018 के पायथन-देव मेलिंग सूची पर "नामकरण समझ वाक्यविन्यास" पर चर्चा है जहां स्थिरता के लिए "जनरेटर समझ" को कॉल करने के लिए अस्थायी लेकिन काफी सर्वसम्मत समझौता था।
हारून हॉल

जवाबों:


144

क्या आप सूची बोध को समझते हैं? यदि हां, तो एक जनरेटर अभिव्यक्ति एक सूची समझ की तरह है, लेकिन उन सभी वस्तुओं को खोजने के बजाय जिन्हें आप रुचि रखते हैं और उन्हें सूची में पैक कर रहे हैं, यह प्रतीक्षा करता है, और प्रत्येक आइटम को अभिव्यक्ति से बाहर निकालता है, एक-एक करके।

>>> my_list = [1, 3, 5, 9, 2, 6]
>>> filtered_list = [item for item in my_list if item > 3]
>>> print(filtered_list)
[5, 9, 6]
>>> len(filtered_list)
3
>>> # compare to generator expression
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> print(filtered_gen)  # notice it's a generator object
<generator object <genexpr> at 0x7f2ad75f89e0>
>>> len(filtered_gen) # So technically, it has no length
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()
>>> # We extract each item out individually. We'll do it manually first.
... 
>>> next(filtered_gen)
5
>>> next(filtered_gen)
9
>>> next(filtered_gen)
6
>>> next(filtered_gen) # Should be all out of items and give an error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> # Yup, the generator is spent. No values for you!
... 
>>> # Let's prove it gives the same results as our list comprehension
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> gen_to_list = list(filtered_gen)
>>> print(gen_to_list)
[5, 9, 6]
>>> filtered_list == gen_to_list
True
>>> 

क्योंकि एक जनरेटर अभिव्यक्ति को केवल एक बार में एक आइटम का उत्पादन करना पड़ता है, इससे मेमोरी उपयोग में बड़ी बचत हो सकती है। जेनरेटर के भाव उन परिदृश्यों में सबसे ज्यादा मायने रखते हैं जहाँ आपको एक समय में एक आइटम लेने की आवश्यकता होती है, उस आइटम के आधार पर बहुत सारी गणनाएँ करें और फिर अगले आइटम पर जाएँ। यदि आपको एक से अधिक मूल्य की आवश्यकता है, तो आप एक जनरेटर अभिव्यक्ति का उपयोग भी कर सकते हैं और एक बार में कुछ हड़प सकते हैं। यदि आपको अपने कार्यक्रम के आगे बढ़ने से पहले सभी मूल्यों की आवश्यकता है, तो इसके बजाय सूची समझ का उपयोग करें।


3
एक सवाल यहां। मैंने परिणाम प्राप्त करने के लिए अगली (gen_name) का उपयोग किया और यह पायथन 3 में काम किया। क्या कोई विशिष्ट परिदृश्य है जहां हमें __next __ () का उपयोग करने की आवश्यकता है?
अंकित वशिष्ठ

2
@AnkitVashistha नहीं, हमेशा पायथन 3 के next(...)बजाय उपयोग करें .__next__()
टोड सिवेल

@AnkitVashistha @gotgenes If you need more than one value, you can also use a generator expression and grab a few at a time। क्या आप इस उपयोग के बारे में एक उदाहरण दे सकते हैं? धन्यवाद।
लिटिलजेरो सेप

19

एक जनरेटर समझ एक सूची समझ का आलसी संस्करण है।

यह सूची बोध के समान है, सिवाय इसके कि यह सूची के बजाय एक पुनरावृत्तिकर्ता को लौटाता है अर्थात अगली () विधि वाली कोई वस्तु जिससे अगला तत्व निकलेगा।

यदि आप सूची बोध से परिचित नहीं हैं, तो यहाँ और जनरेटर यहाँ देखें ।


4

सूची / जनरेटर की समझ एक निर्माण है जिसका उपयोग आप मौजूदा सूची से एक नई सूची / जनरेटर बनाने के लिए कर सकते हैं।

मान लें कि आप 1 से 10 तक प्रत्येक संख्या के वर्गों की सूची बनाना चाहते हैं। आप पायथन में यह कर सकते हैं:

>>> [x**2 for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

यहाँ, range(1,11)सूची बनाता है [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], लेकिन rangeपायथन 3.0 से पहले फ़ंक्शन जनरेटर नहीं है, और इसलिए मैंने जो निर्माण किया है वह एक सूची समझ है।

अगर मैं एक जनरेटर बनाना चाहता था जो एक ही काम करता है, तो मैं इसे इस तरह कर सकता था:

>>> (x**2 for x in xrange(1,11))
<generator object at 0x7f0a79273488>

पाइथन 3 में, हालांकि, rangeएक जनरेटर है, इसलिए परिणाम केवल आपके द्वारा उपयोग किए जाने वाले सिंटैक्स (वर्ग कोष्ठक या गोल कोष्ठक) पर निर्भर करता है।


4
ये गलत है। क्या बाहरी अभिव्यक्ति एक जनरेटर है, इसका आंतरिक अभिव्यक्ति के साथ कोई लेना-देना नहीं है। हालांकि जाहिर है, एक सूची से तत्वों को लेने वाले जनरेटर अभिव्यक्ति में आमतौर पर बहुत अधिक बिंदु नहीं होते हैं, आप यह कर सकते हैं।
एंटीमनी

क्या यह अधिक स्पष्ट रूप से लिखा जा सकता है? मुझे वही मिल रहा है जो आप कह रहे हैं, लेकिन जैसा कि एंटीमनी कहती है, ऐसा लगता है कि आप कुछ और कह रहे हैं। (और जो बात आपको लग रही है, वह गलत है)
लिंडन व्हाइट

3

जनरेटर की समझ एक निश्चित संरचना के साथ जनरेटर बनाने का एक आसान तरीका है। कहते हैं कि आप चाहते हैं generatorकि एक के बाद एक सभी संख्याओं में आउटपुट हो your_list। यदि आप इसे फंक्शन स्टाइल का उपयोग करके बनाते हैं तो यह इस तरह होगा:

def allEvens( L ):
    for number in L:
        if number % 2 is 0:
            yield number

evens = allEvens( yourList )

आप इस जनरेटर समझ अभिव्यक्ति के साथ एक ही परिणाम प्राप्त कर सकते हैं:

evens = ( number for number in your_list if number % 2 == 0 )

दोनों मामलों में, जब आप कॉल next(evens)करते हैं तो आपको अगला नंबर भी मिलता है your_list


0

जेनरेटर कॉम्प्रिहेंशन iterables बनाने के लिए एक दृष्टिकोण है, एक कर्सर जैसा कुछ है जो एक संसाधन पर चलता है। यदि आप mysql कर्सर या मोनगोडब कर्सर को जानते हैं, तो आप इस बात से अवगत हो सकते हैं कि पूरा वास्तविक डेटा कभी भी मेमोरी में लोड नहीं होता है, लेकिन एक बार में। आपका कर्सर आगे और पीछे चलता है, लेकिन मेमोरी में हमेशा एक पंक्ति / सूची तत्व होता है।

संक्षेप में, जनरेटर की समझ का उपयोग करके आप आसानी से अजगर में अभिशाप पैदा कर सकते हैं।


-1

जनरेटर की समझ का एक और उदाहरण:

print 'Generator comprehensions'

def sq_num(n):
    for num in (x**2 for x in range(n)):    
        yield num

for x in sq_num(10):
    print x 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.