पायथन में जेनरेटर

पायथन में जेनरेटर

यह लेख पायथन में जेनरेटर को समझाता है।

YouTube Video

पायथन में जेनरेटर

सामान्य परिचय

पायथन के जेनरेटर एक प्रकार के इटेरेटर हैं और दोहराव वाले प्रोसेसिंग को कुशलतापूर्वक करने के लिए एक शक्तिशाली सुविधा हैं। वे आपको बड़े डेटा के साथ काम करते समय मेमोरी-कुशल कोड लिखने में सक्षम बनाते हैं।

जेनरेटर क्या है?

पायथन में जेनरेटर एक विशेष फंक्शन है जो एक बार में एक मान उत्पन्न करता है, जिसे yield कीवर्ड के साथ परिभाषित किया जाता है। इसकी विशेषता यह है कि यह अपनी स्थिति को बनाए रखते हुए निष्पादन को रोक देता है और बाद में फिर से शुरू कर सकता है।

yield के मूलभूत सिद्धांत

yield एक कीवर्ड है जो एक मान लौटाता है और फंक्शन के निष्पादन को एक साथ रोक देता है

 1def simple_generator():
 2    yield 1
 3    yield 2
 4    yield 3
 5
 6gen = simple_generator()
 7
 8print(next(gen))  # 1
 9print(next(gen))  # 2
10print(next(gen))  # 3
  • जब इस फंक्शन को कॉल किया जाता है, तो यह एक जेनरेटर ऑब्जेक्ट लौटाता है जो मानों को एक-एक करके देता है।
  • next() को तब कॉल करने पर जब अगला मान उपलब्ध नहीं होता है, तो StopIteration त्रुटि उत्पन्न होगी।

next() और StopIteration

 1def simple_generator():
 2    yield 1
 3    yield 2
 4    yield 3
 5
 6gen = simple_generator()
 7
 8try:
 9    while True:
10        value = next(gen)
11        print(value)
12except StopIteration:
13    print("Finished")
  • इस तरह StopIteration त्रुटि को स्पष्ट रूप से संभालकर, आप पता लगा सकते हैं कि जेनरेटर कब समाप्त हो गया है।

send(value)

send(value) को कॉल करने से जनरेटर फिर से शुरू होता है और value को yield अभिव्यक्ति की स्थिति पर भेजता है। भेजे गए मान को जनरेटर पक्ष में yield अभिव्यक्ति के रिटर्न मान के रूप में प्राप्त किया जा सकता है। पहली बार कॉल करते समय, आप send(value) के साथ None के अलावा कुछ भी नहीं भेज सकते, इसलिए आपको next() या send(None) का उपयोग करना चाहिए।

 1def gen():
 2    x = yield 1
 3    print(f"x = {x}")
 4    y = yield 2
 5    print(f"y = {y}")
 6
 7g = gen()
 8print(next(g))       # -> 1 (value from yield 1)
 9print(g.send(10))    # -> x = 10, 2 (value from yield 2)
10print(g.send(20))    # -> y = 20, StopIteration occurs
  • send(10) के साथ, जनरेटर का yield एक ऐसी अभिव्यक्ति बन जाती है जो 10 लौटाती है, और 10 को x में असाइन किया जाता है।

throw()

throw को कॉल करने से जनरेटर फिर से चालू होता है और रुकी हुई yield की स्थिति पर एक अपवाद उत्पन्न होता है। आप जनरेटर के अंदर अपवाद को संभाल सकते हैं ताकि प्रक्रिया जारी रखी जा सके। यदि अपवाद को नहीं पकड़ा गया, तो यह बाहर फैल जाता है और जनरेटर समाप्त हो जाता है।

 1def gen():
 2    try:
 3        yield 1
 4    except ValueError as e:
 5        print(f"Caught: {e}")
 6        yield "recovered"
 7
 8g = gen()
 9print(next(g))   # -> 1
10print(g.throw(ValueError("boom")))  # -> Caught: boom, "recovered"
  • इस कोड में, जनरेटर में अपवाद डालने के लिए throw को कॉल किया गया है। जनरेटर पक्ष में, अपवाद को संभाला जाता है और recovered लौटाया जाता है।

close()

close() को कॉल करने से जनरेटर समाप्त हो जाता है। जनरेटर के अंदर, आप finally का उपयोग करके क्लीनअप कर सकते हैं। close() को कॉल करने के बाद next() या send() को कॉल करने से StopIteration त्रुटि उत्पन्न होती है।

1def gen():
2    try:
3        yield 1
4    finally:
5        print("Cleaning up...")
6
7g = gen()
8print(next(g))  # -> 1
9g.close()       # -> Cleaning up...
  • यह कोड दिखाता है कि close() को कॉल करने से जनरेटर समाप्त हो जाता है और finally में क्लीनअप प्रक्रिया शुरू हो जाती है।

yield from

yield from वह सिंटैक्स है जिसका उपयोग एक सबजेनरेटर को कार्य सौंपने के लिए किया जाता है। यह एक जेनरेटर के अंदर दूसरे जेनरेटर को कॉल करने और उसकी सभी वैल्यूज़ को बाहरी स्कोप तक पहुँचाने का एक सरल तरीका है।

1def sub_gen():
2    yield 1
3    yield 2
4
5def main_gen():
6    yield from sub_gen()
7    yield 3
8
9print(list(main_gen()))  # -> [1, 2, 3]
  • यह कोड yield from का उपयोग करते हुए सबजेनरेटर की सभी वैल्यूज़ को बाहरी जेनरेटर को सौंपता है, और फिर 3 को यील्ड करता है।

इटेरेटर के साथ संबंध

जेनरेटर आंतरिक रूप से __iter__() और __next__() को लागू करते हैं, जिससे वे इटेरेटर का एक प्रकार बन जाते हैं। इसलिए, वे for लूप जैसी इटेरेबल कार्रवाइयों के साथ पूरी तरह संगत हैं।

for लूप के साथ एकीकरण

पायथन में, for लूप आंतरिक रूप से next() का उपयोग मानों को अपने आप प्राप्त करने के लिए करता है।

1def simple_generator():
2    yield 1
3    yield 2
4    yield 3
5
6for value in simple_generator():
7    print(value)

इस विधि के साथ, StopIteration का प्रबंधन भी अपने आप हो जाता है।

अनंत जेनरेटर बनाना

1def count_up(start=0):
2    while True:
3        yield start
4        start += 1
5
6counter = count_up()
7print(next(counter))  # 0
8print(next(counter))  # 1

अनंत लूप बनाना संभव है, लेकिन उनका उपयोग करते समय सावधानी बरतनी चाहिए।

जेनरेटर एक्सप्रेशन

जेनरेटर एक्सप्रेशन, जिन्हें कोष्ठक का उपयोग करके लिखा जाता है, आपको लिस्ट कॉम्प्रिहेंशन जैसी सिंटैक्स के साथ जेनरेटर परिभाषित करने की सुविधा देते हैं।

1# List comprehension (generates the entire list at once)
2squares_list = [x**2 for x in range(5)]
3print(squares_list)
4
5# Generator expression
6squares_gen = (x**2 for x in range(5))
7for square in squares_gen:
8    print(square)

लिस्ट कॉम्प्रिहेंशन के विपरीत, वे सभी तत्वों को एक साथ मेमोरी में लोड नहीं करते, जिससे वे अधिक मेमोरी-कुशल होते हैं।

जेनरेटर में त्रुटि-संभालना

जेनरेटर के अंदर अपवाद हो सकते हैं। ऐसे मामलों में, आप सामान्य पायथन कोड की तरह try-except का उपयोग करते हैं।

 1def safe_divide_generator(numbers, divisor):
 2    """Yields results of dividing numbers by a given divisor safely."""
 3    for number in numbers:
 4        try:
 5            yield number / divisor  # Attempt to divide and yield result.
 6        except ZeroDivisionError:
 7            yield float('inf')  # Return infinity if division by zero occurs.
 8
 9# Example usage
10numbers = [10, 20, 30]
11gen = safe_divide_generator(numbers, 0)  # Create generator with divisor as 0.
12for value in gen:
13    print(value)  # Output: inf, inf, inf

इस उदाहरण में, शून्य से विभाजन की स्थिति में उचित त्रुटि-संभालना की जाती है।

जेनरेटर का स्टैक ट्रेस

अगर जेनरेटर के अंदर कोई अपवाद उत्पन्न होता है, तो जब जेनरेटर फिर से शुरू किया जाता है तब वह अपवाद उठाया जाएगा।

 1def error_generator():
 2    """A generator that yields values and raises an error."""
 3    yield 1
 4    raise ValueError("An error occurred")  # Raise a ValueError intentionally.
 5    yield 2
 6
 7gen = error_generator()
 8print(next(gen))       # Output: 1 (first value yielded)
 9try:
10    print(next(gen))   # Attempt to get the next value, which raises an error
11except ValueError as e:
12    print(e)           # Output: An error occurred (exception message is printed)
  • यह जेनरेटर सबसे पहले 1 लौटाता है। फिर से शुरू करते समय उठी त्रुटि को पकड़ा जाता है और उसे एक त्रुटि संदेश के रूप में दिखाया जाता है।

जेनरेटर के उपयोग के उदाहरण

एक फाइल को लाइन दर लाइन पढ़ना (बड़ी फाइलों के लिए उपयुक्त)

1def read_large_file(filepath):
2    with open(filepath, 'r') as f:
3        for line in f:
4            yield line.strip()
  • यह फंक्शन एक इटरेटर का उपयोग करके टेक्स्ट फ़ाइल को पंक्ति दर पंक्ति पढ़ता है, प्रत्येक पंक्ति से व्हाइटस्पेस हटाता है, और उसे जेनरेटर के रूप में लौटाता है, जिससे बड़ी फ़ाइलों को कम मेमोरी उपयोग के साथ प्रोसेस किया जा सकता है।

फिबोनाच्ची अनुक्रम के लिए जेनरेटर

1def fibonacci(limit):
2    a, b = 0, 1
3    while a < limit:
4        yield a
5        a, b = b, a + b
6
7for n in fibonacci(100):
8    print(n)
  • यह कोड एक जेनरेटर का उपयोग करके क्रमशः ऊपरी सीमा से कम फिबोनाच्ची संख्याएँ उत्पन्न करता है और उन्हें for लूप का उपयोग कर प्रदर्शित करता है।

उपयोग के मामले

जनरेटरों का उपयोग निम्नलिखित परिस्थितियों में भी किया जा सकता है।

  • बड़ी CSV या लॉग फाइलों का क्रमवार प्रोसेसिंग
  • API पेजिनेशन
  • स्ट्रीमिंग डेटा प्रोसेसिंग (जैसे, Kafka, IoT डिवाइस)

सारांश

संकल्पना मुख्य बिंदु
yield रोकता है और एक मान लौटाता है
जेनरेटर फंक्शन एक ऐसा फंक्शन जिसमें yield होता है और उसे कॉल करने पर एक इटेरेटर लौटाता है
फायदे मेमोरी-कुशल और बड़े डेटा सेट के प्रोसेसिंग के लिए आदर्श
जेनरेटर एक्सप्रेशन (x for x in iterable) जैसी संक्षिप्त सिंटैक्स की अनुमति देता है

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

आप हमारे YouTube चैनल पर Visual Studio Code का उपयोग करके ऊपर दिए गए लेख के साथ आगे बढ़ सकते हैं। कृपया YouTube चैनल को भी देखें।

YouTube Video