इस ट्यूटोरियल में, आप सीखेंगे कि पायथन जनरेटर का उपयोग करके आसानी से पुनरावृत्तियों को कैसे बनाया जाए, यह कैसे पुनरावृत्तियों और सामान्य कार्यों से अलग है, और आपको इसका उपयोग क्यों करना चाहिए।
वीडियो: पायथन जेनरेटर
पायथन में जनरेटर
पायथन में एक इट्रेटर के निर्माण में बहुत काम है। हमें एक वर्ग को लागू करना होगा __iter__()
और __next__()
विधि के साथ , आंतरिक राज्यों का ध्यान रखना होगा, और उठाना होगा StopIteration
जब कोई मूल्य वापस नहीं करना है।
यह लंबा और उल्टा दोनों प्रकार का है। ऐसी स्थितियों में जेनरेटर बचाव के लिए आता है।
पायथन जनरेटर पुनरावृत्तियों को बनाने का एक सरल तरीका है। हमारे द्वारा ऊपर वर्णित सभी कार्य स्वचालित रूप से पायथन में जनरेटर द्वारा नियंत्रित किए जाते हैं।
सीधे शब्दों में, एक जनरेटर एक फ़ंक्शन है जो एक वस्तु (पुनरावृत्ति) लौटाता है जिसे हम एक समय में (एक मान) ओवररेट कर सकते हैं।
पायथन में जनरेटर बनाएँ
पायथन में एक जनरेटर बनाना काफी सरल है। यह एक सामान्य कार्य को परिभाषित करने के रूप में आसान है, लेकिन एक yield
बयान के बजाय एक return
बयान के साथ।
यदि किसी फ़ंक्शन में कम से कम एक yield
कथन है (इसमें अन्य yield
या return
कथन हो सकते हैं ), तो यह एक जनरेटर फ़ंक्शन बन जाता है। दोनों yield
और return
एक समारोह से कुछ मान प्रदान करेंगे।
अंतर यह है कि जबकि एक return
बयान पूरी तरह से एक फ़ंक्शन को समाप्त करता है, yield
स्टेटमेंट फ़ंक्शन को उसके सभी राज्यों को बचाने के लिए रोक देता है और बाद में क्रमिक कॉल पर वहां से जारी रहता है।
जेनरेटर फंक्शन और नॉर्मल फंक्शन के बीच अंतर
यहां बताया गया है कि एक जनरेटर फ़ंक्शन एक सामान्य फ़ंक्शन से कैसे भिन्न होता है।
- जेनरेटर फ़ंक्शन में एक या अधिक
yield
कथन होते हैं। - जब कहा जाता है, तो यह एक वस्तु (पुनरावृत्ति) लौटाता है लेकिन तुरंत निष्पादन शुरू नहीं करता है।
- जैसे तरीके
__iter__()
और__next__()
अपने आप लागू हो जाते हैं। तो हम उपयोग कर रहे आइटम के माध्यम से पुनरावृति कर सकते हैंnext()
। - एक बार फ़ंक्शन की पैदावार होने पर, फ़ंक्शन को रोक दिया जाता है और कॉल करने वाले को नियंत्रण स्थानांतरित कर दिया जाता है।
- स्थानीय चर और उनके राज्य क्रमिक कॉल के बीच याद किए जाते हैं।
- अंत में, जब फ़ंक्शन समाप्त हो जाता है,
StopIteration
तो आगे की कॉल पर स्वचालित रूप से उठाया जाता है।
यहाँ ऊपर वर्णित सभी बिंदुओं को स्पष्ट करने के लिए एक उदाहरण दिया गया है। हमारे पास एक जनरेटर फ़ंक्शन है जिसका नाम my_gen()
कई yield
बयानों के साथ है ।
# A simple generator function def my_gen(): n = 1 print('This is printed first') # Generator function contains yield statements yield n n += 1 print('This is printed second') yield n n += 1 print('This is printed at last') yield n
दुभाषिया में एक इंटरैक्टिव रन नीचे दिया गया है। आउटपुट देखने के लिए इन्हें पायथन शेल में चलाएं।
>>> # It returns an object but does not start execution immediately. >>> a = my_gen() >>> # We can iterate through the items using next(). >>> next(a) This is printed first 1 >>> # Once the function yields, the function is paused and the control is transferred to the caller. >>> # Local variables and theirs states are remembered between successive calls. >>> next(a) This is printed second 2 >>> next(a) This is printed at last 3 >>> # Finally, when the function terminates, StopIteration is raised automatically on further calls. >>> next(a) Traceback (most recent call last):… StopIteration >>> next(a) Traceback (most recent call last):… StopIteration
उपरोक्त उदाहरण में ध्यान देने वाली एक दिलचस्प बात यह है कि प्रत्येक कॉल के बीच वेरिएबल एन का मूल्य याद किया जाता है।
सामान्य कार्यों के विपरीत, फ़ंक्शन के पैदावार होने पर स्थानीय चर नष्ट नहीं होते हैं। इसके अलावा, जनरेटर वस्तु को केवल एक बार पुनरावृत्त किया जा सकता है।
इस प्रक्रिया को पुनः आरंभ करने के लिए हमें किसी अन्य जनरेटर वस्तु को बनाने की आवश्यकता है जैसे कुछ का उपयोग करके a = my_gen()
।
ध्यान देने वाली एक अंतिम बात यह है कि हम सीधे लूप के लिए जनरेटर का उपयोग कर सकते हैं।
ऐसा इसलिए है क्योंकि एक for
लूप एक पुनरावृत्ति लेता है और next()
फ़ंक्शन का उपयोग करके उस पर पुनरावृति करता है। StopIteration
उठने पर यह अपने आप समाप्त हो जाता है। यह जानने के लिए यहां देखें कि वास्तव में पायथन में लूप कैसे लागू किया जाता है।
# A simple generator function def my_gen(): n = 1 print('This is printed first') # Generator function contains yield statements yield n n += 1 print('This is printed second') yield n n += 1 print('This is printed at last') yield n # Using for loop for item in my_gen(): print(item)
जब आप प्रोग्राम चलाते हैं, तो आउटपुट होगा:
यह पहले 1 छपा है। यह दूसरा 2 छपा है। यह अंतिम 3 पर छपा है
लूप के साथ पायथन जेनरेटर
उपरोक्त उदाहरण कम उपयोग का है और हमने इसका अध्ययन सिर्फ यह जानने के लिए किया कि पृष्ठभूमि में क्या हो रहा था।
आमतौर पर, जनरेटर कार्यों को एक उपयुक्त समाप्ति स्थिति वाले लूप के साथ लागू किया जाता है।
चलो एक जनरेटर का एक उदाहरण लेते हैं जो एक स्ट्रिंग को उलट देता है।
def rev_str(my_str): length = len(my_str) for i in range(length - 1, -1, -1): yield my_str(i) # For loop to reverse the string for char in rev_str("hello"): print(char)
आउटपुट
ओलेह
इस उदाहरण में, हमने range()
लूप के लिए इंडेक्स को रिवर्स ऑर्डर में प्राप्त करने के लिए फ़ंक्शन का उपयोग किया है।
Note: This generator function not only works with strings, but also with other kinds of iterables like list, tuple, etc.
Python Generator Expression
Simple generators can be easily created on the fly using generator expressions. It makes building generators easy.
Similar to the lambda functions which create anonymous functions, generator expressions create anonymous generator functions.
The syntax for generator expression is similar to that of a list comprehension in Python. But the square brackets are replaced with round parentheses.
The major difference between a list comprehension and a generator expression is that a list comprehension produces the entire list while the generator expression produces one item at a time.
They have lazy execution ( producing items only when asked for ). For this reason, a generator expression is much more memory efficient than an equivalent list comprehension.
# Initialize the list my_list = (1, 3, 6, 10) # square each term using list comprehension list_ = (x**2 for x in my_list) # same thing can be done using a generator expression # generator expressions are surrounded by parenthesis () generator = (x**2 for x in my_list) print(list_) print(generator)
Output
(1, 9, 36, 100)
We can see above that the generator expression did not produce the required result immediately. Instead, it returned a generator object, which produces items only on demand.
Here is how we can start getting items from the generator:
# Initialize the list my_list = (1, 3, 6, 10) a = (x**2 for x in my_list) print(next(a)) print(next(a)) print(next(a)) print(next(a)) next(a)
When we run the above program, we get the following output:
1 9 36 100 Traceback (most recent call last): File "", line 15, in StopIteration
Generator expressions can be used as function arguments. When used in such a way, the round parentheses can be dropped.
>>> sum(x**2 for x in my_list) 146 >>> max(x**2 for x in my_list) 100
Use of Python Generators
There are several reasons that make generators a powerful implementation.
1. Easy to Implement
Generators can be implemented in a clear and concise way as compared to their iterator class counterpart. Following is an example to implement a sequence of power of 2 using an iterator class.
class PowTwo: def __init__(self, max=0): self.n = 0 self.max = max def __iter__(self): return self def __next__(self): if self.n> self.max: raise StopIteration result = 2 ** self.n self.n += 1 return result
The above program was lengthy and confusing. Now, let's do the same using a generator function.
def PowTwoGen(max=0): n = 0 while n < max: yield 2 ** n n += 1
Since generators keep track of details automatically, the implementation was concise and much cleaner.
2. Memory Efficient
A normal function to return a sequence will create the entire sequence in memory before returning the result. This is an overkill, if the number of items in the sequence is very large.
Generator implementation of such sequences is memory friendly and is preferred since it only produces one item at a time.
3. Represent Infinite Stream
जेनरेटर डेटा की अनंत धारा का प्रतिनिधित्व करने के लिए उत्कृष्ट माध्यम हैं। अनंत धाराओं को मेमोरी में संग्रहीत नहीं किया जा सकता है, और चूंकि जनरेटर एक बार में केवल एक आइटम का उत्पादन करते हैं, वे डेटा की एक अनंत धारा का प्रतिनिधित्व कर सकते हैं।
निम्नलिखित जनरेटर फ़ंक्शन सभी समान संख्याएं उत्पन्न कर सकता है (कम से कम सिद्धांत रूप में)।
def all_even(): n = 0 while True: yield n n += 2
4. पाइपलाइनिंग जेनरेटर
कई जनरेटर का उपयोग ऑपरेशन की एक श्रृंखला को पाइपलाइन करने के लिए किया जा सकता है। यह एक उदाहरण का उपयोग करके सबसे अच्छा सचित्र है।
मान लीजिए कि हमारे पास एक जनरेटर है जो फाइबोनैचि श्रृंखला में संख्या पैदा करता है। और हमारे पास स्क्वेरिंग संख्याओं के लिए एक और जनरेटर है।
यदि हम फाइबोनैचि श्रृंखला में संख्याओं के योग का पता लगाना चाहते हैं, तो हम इसे जनरेटर कार्यों के आउटपुट को एक साथ जोड़कर निम्न तरीके से कर सकते हैं।
def fibonacci_numbers(nums): x, y = 0, 1 for _ in range(nums): x, y = y, x+y yield x def square(nums): for num in nums: yield num**2 print(sum(square(fibonacci_numbers(10))))
आउटपुट
4895 है
यह पाइपलाइनिंग कुशल और पढ़ने में आसान है (और हाँ, बहुत कूलर!)।