पायथन के जेनरेटर और इटरेटर के बीच अंतर


537

पुनरावृत्तियों और जनरेटर के बीच अंतर क्या है? जब आप प्रत्येक मामले का उपयोग करेंगे तो कुछ उदाहरण सहायक होंगे।

जवाबों:


542

iteratorएक अधिक सामान्य अवधारणा है: कोई भी वस्तु जिसकी कक्षा में एक nextविधि है ( __next__पायथन 3 में) और एक __iter__विधि जो करती है return self

हर जेनरेटर एक इटरेटर है, लेकिन इसके विपरीत नहीं। एक जनरेटर एक फ़ंक्शन को कॉल करके बनाया गया है जिसमें एक या एक से अधिक yieldअभिव्यक्ति ( yieldबयान, पायथन 2.5 और पूर्व में) हैं, और एक ऑब्जेक्ट है जो पिछले पैराग्राफ की परिभाषा से मिलता है iterator

आप एक जनरेटर के बजाय एक कस्टम पुनरावृत्ति का उपयोग करना चाह सकते हैं, जब आपको कुछ जटिल राज्य बनाए रखने वाले व्यवहार के साथ एक वर्ग की आवश्यकता होती है, या next( __iter__और __init__) के अलावा अन्य तरीकों को उजागर करना चाहते हैं । सबसे अधिक बार, एक जनरेटर (कभी-कभी, पर्याप्त रूप से सरल आवश्यकताओं के लिए, एक जनरेटर अभिव्यक्ति ) पर्याप्त होता है, और यह कोड के लिए सरल होता है क्योंकि राज्य के रखरखाव (उचित सीमा के भीतर) मूल रूप से निलंबित और फिर से शुरू होने वाले फ्रेम द्वारा "आपके लिए" किया जाता है।

उदाहरण के लिए, एक जनरेटर जैसे:

def squares(start, stop):
    for i in range(start, stop):
        yield i * i

generator = squares(a, b)

या समकक्ष जनरेटर अभिव्यक्ति (जीनएक्सपी)

generator = (i*i for i in range(a, b))

एक कस्टम पुनरावृत्ति के रूप में बनाने के लिए अधिक कोड ले जाएगा:

class Squares(object):
    def __init__(self, start, stop):
       self.start = start
       self.stop = stop
    def __iter__(self): return self
    def next(self): # __next__ in Python 3
       if self.start >= self.stop:
           raise StopIteration
       current = self.start * self.start
       self.start += 1
       return current

iterator = Squares(a, b)

लेकिन, निश्चित रूप से, वर्ग के साथ Squaresआप आसानी से अतिरिक्त तरीकों की पेशकश कर सकते हैं, अर्थात

    def current(self):
       return self.start

यदि आपको अपने आवेदन में ऐसी अतिरिक्त कार्यक्षमता के लिए कोई वास्तविक आवश्यकता है।


एक बार मैंने इसे बनाने के बाद, मैं पुनरावृत्ति का उपयोग कैसे करूं?
विन्सेन्जुओ

@Vincenzooo जो आप इसके साथ क्या करना चाहते हैं पर निर्भर करता है। यह या तो for ... in ...:एक समारोह का हिस्सा हो जाएगा , या आप कॉल कर रहे होंगेiter.next()
केल

@ कैलेथ मैं सटीक सिंटैक्स के बारे में पूछ रहा था, क्योंकि मुझे for..inसिंटैक्स का उपयोग करने की कोशिश में त्रुटि हो रही थी । शायद मैं कुछ याद कर रहा था, लेकिन यह कुछ समय पहले था, मैं हल नहीं करता अगर मैं हल करता हूं। धन्यवाद!
विंसेंजियो

135

पुनरावृत्तियों और जनरेटर के बीच अंतर क्या है? जब आप प्रत्येक मामले का उपयोग करेंगे तो कुछ उदाहरण सहायक होंगे।

सारांश में: Iterators वस्तुओं है कि एक कर रहे हैं __iter__और एक __next__( nextपायथन में 2) विधि। जनरेटर Iterators के उदाहरण बनाने के लिए एक आसान, अंतर्निहित तरीका प्रदान करते हैं।

इसमें उपज के साथ एक फ़ंक्शन अभी भी एक फ़ंक्शन है, जिसे जब बुलाया जाता है, तो जनरेटर ऑब्जेक्ट का एक उदाहरण देता है:

def a_function():
    "when called, returns generator object"
    yield

एक जनरेटर अभिव्यक्ति भी एक जनरेटर देता है:

a_generator = (i for i in range(0))

अधिक गहराई से व्याख्या और उदाहरण के लिए, पढ़ते रहें।

एक जनरेटर है एक इटरेटर

विशेष रूप से, जनरेटर पुनरावृत्ति का एक उपप्रकार है।

>>> import collections, types
>>> issubclass(types.GeneratorType, collections.Iterator)
True

हम एक जनरेटर कई तरीके बना सकते हैं। ऐसा करने के लिए एक बहुत ही सामान्य और सरल तरीका एक फ़ंक्शन के साथ है।

विशेष रूप से, इसमें उपज वाला एक फ़ंक्शन एक फ़ंक्शन है, जिसे जब बुलाया जाता है, तो एक जनरेटर देता है:

>>> def a_function():
        "just a function definition with yield in it"
        yield
>>> type(a_function)
<class 'function'>
>>> a_generator = a_function()  # when called
>>> type(a_generator)           # returns a generator
<class 'generator'>

और एक जनरेटर, फिर से, एक Iterator है:

>>> isinstance(a_generator, collections.Iterator)
True

एक इटरेटर है एक Iterable

एक Iterator एक Iterable है,

>>> issubclass(collections.Iterator, collections.Iterable)
True

जिसके लिए एक __iter__विधि की आवश्यकता होती है जो एक Iterator देता है:

>>> collections.Iterable()
Traceback (most recent call last):
  File "<pyshell#79>", line 1, in <module>
    collections.Iterable()
TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__

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

>>> all(isinstance(element, collections.Iterable) for element in (
        (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True

Iterators एक या विधि की आवश्यकता हैnext__next__

पायथन 2 में:

>>> collections.Iterator()
Traceback (most recent call last):
  File "<pyshell#80>", line 1, in <module>
    collections.Iterator()
TypeError: Can't instantiate abstract class Iterator with abstract methods next

और पायथन 3 में:

>>> collections.Iterator()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Iterator with abstract methods __next__

हम iterफ़ंक्शन के साथ अंतर्निहित ऑब्जेक्ट्स (या कस्टम ऑब्जेक्ट) से पुनरावृत्तियों को प्राप्त कर सकते हैं :

>>> all(isinstance(iter(element), collections.Iterator) for element in (
        (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True

__iter__विधि कहा जाता है जब आप एक के लिए लूप के साथ एक वस्तु का उपयोग करने का प्रयास। फिर __next__विधि को प्रत्येक वस्तु को लूप से बाहर निकालने के लिए पुनरावृति वस्तु पर बुलाया जाता है। StopIterationजब आप इसे समाप्त कर चुके हैं, तो इट्रेटर उठता है, और उस बिंदु पर इसका पुन: उपयोग नहीं किया जा सकता है।

प्रलेखन से

Iterator के जेनरेटर के प्रकार खंड से बिल्ट-इन प्रकार के डॉक्यूमेंट के सेक्शन :

पायथन के जनरेटर इटरेटर प्रोटोकॉल को लागू करने का एक सुविधाजनक तरीका प्रदान करते हैं। यदि एक कंटेनर ऑब्जेक्ट की __iter__()विधि को एक जनरेटर के रूप में लागू किया जाता है, तो यह स्वचालित रूप से एक इट्रेटर ऑब्जेक्ट (तकनीकी रूप से, एक जनरेटर ऑब्जेक्ट) __iter__()और next()( __next__()पायथन 3 में) विधियों की आपूर्ति करेगा । उपज अभिव्यक्ति के लिए प्रलेखन में जनरेटर के बारे में अधिक जानकारी प्राप्त की जा सकती है।

(महत्व दिया।)

तो इससे हमें पता चलता है कि जेनरेटर एक (सुविधाजनक) प्रकार का Iterator है।

उदाहरण Iterator वस्तुएँ

आप ऑब्जेक्ट को बना सकते हैं जो Iterator प्रोटोकॉल को लागू करता है या आपकी स्वयं की ऑब्जेक्ट को बढ़ाकर या बढ़ाकर।

class Yes(collections.Iterator):

    def __init__(self, stop):
        self.x = 0
        self.stop = stop

    def __iter__(self):
        return self

    def next(self):
        if self.x < self.stop:
            self.x += 1
            return 'yes'
        else:
            # Iterators must raise when done, else considered broken
            raise StopIteration

    __next__ = next # Python 3 compatibility

लेकिन ऐसा करने के लिए जेनरेटर का उपयोग करना आसान है:

def yes(stop):
    for _ in range(stop):
        yield 'yes'

या शायद सरल, एक जेनरेटर अभिव्यक्ति (सूची बोध के समान काम करता है):

yes_expr = ('yes' for _ in range(stop))

वे सभी एक ही तरीके से उपयोग किए जा सकते हैं:

>>> stop = 4             
>>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop), 
                             ('yes' for _ in range(stop))):
...     print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3))
...     
0: yes == yes == yes
1: yes == yes == yes
2: yes == yes == yes
3: yes == yes == yes

निष्कर्ष

जब आप पायथन ऑब्जेक्ट को एक ऑब्जेक्ट के रूप में विस्तारित करने की आवश्यकता हो तो आप सीधे इटरेटर प्रोटोकॉल का उपयोग कर सकते हैं।

हालाँकि, अधिकांश मामलों में, आप yieldएक ऐसे फ़ंक्शन को परिभाषित करने के लिए उपयोग करने के लिए सबसे उपयुक्त हैं जो जेनरेटर इटरेटर लौटाता है या जेनरेटर एक्सप्रेशंस पर विचार करता है।

अंत में, ध्यान दें कि जनरेटर कोरटाइन के रूप में और भी अधिक कार्यक्षमता प्रदान करते हैं। मैं yieldविवरण के साथ जेनरेटर की व्याख्या करता हूं , "उत्तर" उपज "कीवर्ड क्या करता है?"


41

iterators:

इटरेटर ऐसी वस्तुएं हैं जो next()अनुक्रम के अगले मूल्य प्राप्त करने के लिए विधि का उपयोग करती हैं।

जेनरेटर:

एक जनरेटर एक फ़ंक्शन है जो yieldविधि का उपयोग करके मूल्यों के अनुक्रम का उत्पादन या पैदावार करता है ।

next()जनरेटर विधि पर प्रत्येक विधि कॉल ( fउदाहरण के लिए : नीचे उदाहरण में) जनरेटर फ़ंक्शन द्वारा लौटाया गया ( foo()उदाहरण के लिए : नीचे उदाहरण में फ़ंक्शन), क्रम में अगला मान उत्पन्न करता है।

जब एक जनरेटर फ़ंक्शन कहा जाता है, तो यह फ़ंक्शन के निष्पादन की शुरुआत के बिना एक जनरेटर ऑब्जेक्ट देता है। जब next()विधि को पहली बार कॉल किया जाता है, तो फ़ंक्शन तब तक निष्पादित करना शुरू कर देता है जब तक कि वह उपज स्टेटमेंट तक नहीं पहुंचता है जो उपज का मूल्य लौटाता है। उपज अंतिम नज़र रखता है यानी याद रखता है। और दूसरा next()कॉल पिछले मूल्य से जारी है।

निम्न उदाहरण उपज के बीच परस्पर क्रिया को प्रदर्शित करता है और जनरेटर ऑब्जेक्ट पर अगली विधि को कॉल करता है।

>>> def foo():
...     print "begin"
...     for i in range(3):
...         print "before yield", i
...         yield i
...         print "after yield", i
...     print "end"
...
>>> f = foo()
>>> f.next()
begin
before yield 0            # Control is in for loop
0
>>> f.next()
after yield 0             
before yield 1            # Continue for loop
1
>>> f.next()
after yield 1
before yield 2
2
>>> f.next()
after yield 2
end
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

3
सिर्फ FYI पैदावार विधि नहीं है, यह कीवर्ड है
Jay Parikh

25

एक उत्तर जोड़ना क्योंकि मौजूदा उत्तरों में से कोई भी विशेष रूप से आधिकारिक साहित्य में भ्रम को संबोधित नहीं करता है।

जेनरेटर फ़ंक्शंस साधारण फ़ंक्शंस हैं जिनकेyieldबजाय काउपयोग करके परिभाषित कियागया हैreturn। जब कहा जाता है, तो एक जनरेटर फ़ंक्शन एक जनरेटर ऑब्जेक्ट लौटाता है, जो एक प्रकार का पुनरावृत्ति है - इसकी एकnext()विधि है। जब आप कॉल करते हैंnext(), तो जनरेटर फ़ंक्शन द्वारा प्राप्त अगला मान वापस आ जाता है।

या तो फ़ंक्शन या ऑब्जेक्ट को "जनरेटर" कहा जा सकता है, जिसके आधार पर पायथन स्रोत दस्तावेज़ आप पढ़ते हैं। अजगर शब्दकोष जनरेटर कार्यों कहते हैं, जबकि अजगर विकी जनरेटर वस्तुओं निकलता है। अजगर ट्यूटोरियल उल्लेखनीय मतलब का प्रबंधन दोनों तीन वाक्यों के अंतरिक्ष में प्रयोग:

जनरेटर पुनरावृत्तियों को बनाने के लिए एक सरल और शक्तिशाली उपकरण है। उन्हें नियमित कार्यों की तरह लिखा जाता है, लेकिन जब भी वे डेटा वापस करना चाहते हैं तो उपज विवरण का उपयोग करते हैं। हर बार अगला () उस पर कॉल किया जाता है, जनरेटर फिर से शुरू होता है जहां इसे छोड़ दिया गया था (यह सभी डेटा मानों को याद करता है और कौन सा विवरण अंतिम बार निष्पादित किया गया था)।

पहले दो वाक्य जनरेटर कार्यों के साथ जनरेटर की पहचान करते हैं, जबकि तीसरा वाक्य जनरेटर वस्तुओं के साथ उनकी पहचान करता है।

इस सभी भ्रम के बावजूद, कोई स्पष्ट और अंतिम शब्द के लिए पायथन भाषा के संदर्भ की तलाश कर सकता है:

उपज अभिव्यक्ति का उपयोग केवल एक जनरेटर फ़ंक्शन को परिभाषित करते समय किया जाता है, और इसका उपयोग केवल फ़ंक्शन परिभाषा के शरीर में किया जा सकता है। फ़ंक्शन परिभाषा में उपज अभिव्यक्ति का उपयोग करना उस परिभाषा को सामान्य फ़ंक्शन के बजाय जनरेटर फ़ंक्शन बनाने के लिए पर्याप्त है।

जब एक जनरेटर फ़ंक्शन कहा जाता है, तो यह एक जनरेटर के रूप में जाना जाने वाला पुनरावृत्ति लौटाता है। वह जनरेटर तब एक जनरेटर फ़ंक्शन के निष्पादन को नियंत्रित करता है।

तो, औपचारिक और सटीक उपयोग में, "जनरेटर" अयोग्य का अर्थ है जनरेटर वस्तु, न कि जनरेटर फ़ंक्शन।

उपरोक्त संदर्भ पायथन 2 के लिए हैं, लेकिन पायथन 3 भाषा संदर्भ एक ही बात कहता है। हालाँकि, पायथन 3 शब्दावली कहती है कि

जनरेटर ... आमतौर पर एक जनरेटर फ़ंक्शन को संदर्भित करता है, लेकिन कुछ संदर्भों में एक जनरेटर पुनरावृत्ति को संदर्भित कर सकता है। ऐसे मामलों में जहां पूरा अर्थ स्पष्ट नहीं है, पूर्ण शब्दों का उपयोग अस्पष्टता से बचा जाता है।


मुझे नहीं लगता कि जेनरेटर फ़ंक्शंस और जनरेटर ऑब्जेक्ट्स के बीच बहुत भ्रम है, इसी कारण से आमतौर पर कक्षाओं और उनके उदाहरणों के बीच कोई भ्रम नहीं है। दोनों ही मामलों में, आप दूसरे को पाने के लिए एक कॉल करते हैं, और आकस्मिक बातचीत (या जल्दी से लिखित प्रलेखन) में आप किसी एक के लिए वर्ग नाम या "जनरेटर" शब्द का उपयोग कर सकते हैं। आपको केवल उन स्थितियों में "जनरेटर फ़ंक्शन" बनाम "जनरेटर ऑब्जेक्ट" के बारे में स्पष्ट होना चाहिए जहां आप मामलों के बारे में बात कर रहे हैं।
ब्लैंकनथ

6
1. इस बात के लिए सैद्धांतिक कारणों के बावजूद कि भ्रम की स्थिति क्यों नहीं होनी चाहिए, इस सवाल के अन्य उत्तरों पर टिप्पणियां अस्वीकार किए बिना एक दूसरे के विरोधाभासी हैं और वास्तविक भ्रम का संकेत देती हैं। 2. आकस्मिक संसेचन ठीक है लेकिन एक सटीक, आधिकारिक स्रोत एसओ पर कम से कम एक विकल्प होना चाहिए। मैं अपनी वर्तमान परियोजना में बड़े पैमाने पर जनरेटर कार्यों और वस्तुओं दोनों का उपयोग करता हूं, और डिजाइन और कोडिंग करते समय भेद बहुत महत्वपूर्ण है। यह जानना अच्छा है कि अब किस शब्दावली का उपयोग करना है, इसलिए मुझे बाद में दर्जनों परिवर्तनशील नामों और टिप्पणियों को बदलने की आवश्यकता नहीं है।
पॉल

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

2
जनरेटर या जनरेटर कार्यों के आसपास से गुजरने वाले उच्च-क्रम के कार्य अजीब लग सकते हैं, लेकिन मेरे लिए वे आ रहे हैं। मैं अपाचे स्पार्क में काम कर रहा हूं और यह एक बहुत ही कार्यात्मक प्रोग्रामिंग शैली को लागू करता है। कार्यों को बनाने, पास करने, और सभी प्रकार की वस्तुओं को पास करने के लिए काम करना पड़ता है। मेरे पास कई परिस्थितियां हैं जहां मैंने "जनरेटर" किस तरह का ट्रैक खो दिया था, मैं इसके साथ काम कर रहा था। चर नामों और टिप्पणियों में संकेत, सुसंगत और सही शब्दावली का उपयोग करते हुए, भ्रम को साफ करने में मदद करते हैं। एक Pythonist की अस्पष्टता दूसरे के प्रोजेक्ट डिज़ाइन का केंद्र हो सकती है!
पॉल

1
@Paul, इस उत्तर को लिखने के लिए धन्यवाद। यह भ्रम महत्वपूर्ण है क्योंकि एक जनरेटर ऑब्जेक्ट और एक जनरेटर फ़ंक्शन के बीच अंतर वांछित व्यवहार प्राप्त करने और जनरेटर को देखने के लिए होने के बीच का अंतर है।
ब्लुजे

16

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

यदि आप अपना स्वयं का पुनरावृत्त बनाते हैं, तो यह थोड़ा सा शामिल है - आपको एक वर्ग बनाना होगा और कम से कम पुनरावृति और अगले तरीकों को लागू करना होगा। लेकिन क्या होगा अगर आप इस परेशानी से नहीं गुजरना चाहते हैं और जल्दी से एक इटेरेटर बनाना चाहते हैं। सौभाग्य से, पायथन एक पुनरावृत्त को परिभाषित करने के लिए एक छोटा रास्ता प्रदान करता है। आपको केवल एक फ़ंक्शन को उपज के लिए कम से कम 1 कॉल के साथ परिभाषित करना होगा और अब जब आप उस फ़ंक्शन को कॉल करते हैं तो यह " कुछ " लौटाएगा जो एक पुनरावृत्ति की तरह काम करेगा (आप अगली विधि को कॉल कर सकते हैं और इसे लूप के लिए उपयोग कर सकते हैं)। इस चीज़ का कुछ नाम पाइथन है जिसका नाम जेनरेटर है

आशा है कि थोड़ा स्पष्ट करता है।


9

पिछले उत्तर इस तरह से चूक गए: एक जनरेटर में एक closeविधि है, जबकि विशिष्ट पुनरावृत्तियों नहीं है। closeविधि चलाता एक StopIterationजनरेटर में अपवाद है, जो एक में पकड़ा जा सकता है finallyकि इटरेटर में खंड, कुछ सफाई को चलाने के लिए एक मौका मिलता है। यह अमूर्तता सरल पुनरावृत्तियों की तुलना में बड़े में सबसे अधिक उपयोगी है। एक जनरेटर को बंद कर सकता है क्योंकि एक फ़ाइल को बंद कर सकता है, इसके बारे में परेशान होने के बिना।

उस ने कहा, पहले प्रश्न के लिए मेरा व्यक्तिगत उत्तर होगा: चलने योग्य केवल एक __iter__विधि है, ठेठ पुनरावृत्तियों में केवल एक __next__विधि है, जनरेटर में एक __iter__और एक दोनों __next__अतिरिक्त हैं close

दूसरे प्रश्न के लिए, मेरा व्यक्तिगत जवाब होगा: एक सार्वजनिक इंटरफ़ेस में, मैं जनरेटर को बहुत अधिक पसंद करता हूं, क्योंकि यह अधिक लचीला है: closeविधि के साथ एक बड़ी रचना yield from। स्थानीय रूप से, मैं पुनरावृत्तियों का उपयोग कर सकता हूं, लेकिन केवल अगर यह एक सपाट और सरल संरचना है (पुनरावृत्त आसानी से रचना नहीं करता है) और यदि यह मानने के कारण हैं कि अनुक्रम विशेष रूप से कम है, खासकर अगर इसे अंत तक पहुंचने से पहले रोका जा सकता है। मैं पुनरावृत्तियों को निम्न स्तर के आदिम के रूप में देखता हूं, सिवाय शाब्दिक के।

नियंत्रण प्रवाह मामलों के लिए, जनरेटर वादों के रूप में एक महत्वपूर्ण अवधारणा है: दोनों अमूर्त और रचना योग्य हैं।


क्या आप रचना के बारे में बात करते समय आपको उदाहरण देने के लिए एक उदाहरण दे सकते हैं? इसके अलावा, क्या आप बता सकते हैं कि " विशिष्ट पुनरावृत्तियों" के बारे में बात करते समय आपके मन में क्या है ?
bli

1
एक अन्य उत्तर ( stackoverflow.com/a/28353158/1878788 ) में कहा गया है कि "एक पुनरावृत्त एक पुनरावृत्त है"। चूँकि एक चलने योग्य के पास एक __iter__विधि है, कैसे एक पुनरावृत्ति आ सकती है __next__? यदि वे पुनरावृत्त होने वाले हैं, तो मैं उनसे अपेक्षा करता हूं कि वे __iter__भी जरूरी हैं ।
bli

1
@bli: AFAICS के इस जवाब में मानक PEP234 का उल्लेख है , इसलिए यह सही है, जबकि अन्य उत्तर कुछ कार्यान्वयन को संदर्भित करता है, इसलिए यह संदिग्ध है। मानक __iter__को पुनरावृति पर केवल पुनरावृत्ती की आवश्यकता होती है, जिसके लिए केवल एक nextविधि ( __next__Python3 में) की आवश्यकता होती है । कृपया उनके कार्यान्वयन के साथ मानकों (बतख टाइपिंग के लिए) को भ्रमित न करें (कैसे एक विशेष पायथन दुभाषिया ने इसे लागू किया)। यह जनरेटर कार्यों (परिभाषा) और जनरेटर ऑब्जेक्ट्स (कार्यान्वयन) के बीच भ्रम की तरह एक सा है। ;)
टीनो

7

जनरेटर समारोह, जनरेटर वस्तु, जनरेटर:

पाइथन में एक जेनरेटर फंक्शन एक नियमित फंक्शन की तरह होता है लेकिन इसमें एक या अधिक yieldस्टेटमेंट्स होते हैं। Iterator वस्तुओं को यथासंभव आसान बनाने के लिए जनरेटर फ़ंक्शन एक महान उपकरण है। इटरेटर जनरेटर समारोह द्वारा वस्तु returend भी कहा जाता है जेनरेटर वस्तु या जेनरेटर

इस उदाहरण में मैंने एक जेनरेटर फंक्शन बनाया है जो जेनरेटर ऑब्जेक्ट देता है <generator object fib at 0x01342480>। अन्य पुनरावृत्तियों की तरह, जेनरेटर ऑब्जेक्ट का उपयोग forलूप में या अंतर्निहित फ़ंक्शन के साथ किया जा सकता है next()जो जनरेटर से अगला मूल्य लौटाता है।

def fib(max):
    a, b = 0, 1
    for i in range(max):
        yield a
        a, b = b, a + b
print(fib(10))             #<generator object fib at 0x01342480>

for i in fib(10):
    print(i)               # 0 1 1 2 3 5 8 13 21 34


print(next(myfib))         #0
print(next(myfib))         #1
print(next(myfib))         #1
print(next(myfib))         #2

तो एक जनरेटर फ़ंक्शन Iterator ऑब्जेक्ट बनाने का सबसे आसान तरीका है।

Iterator :

प्रत्येक जनरेटर वस्तु एक पुनरावृत्ति है लेकिन इसके विपरीत नहीं है। कस्टम इटरेटर ऑब्जेक्ट तब बनाया जा सकता है जब उसकी क्लास इम्प्लीमेंट __iter__और __next__मेथड (इसे इटरेटर प्रोटोकॉल भी कहा जाता है)।

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

class Fib:
    def __init__(self,max):
        self.current=0
        self.next=1
        self.max=max
        self.count=0

    def __iter__(self):
        return self

    def __next__(self):
        if self.count>self.max:
            raise StopIteration
        else:
            self.current,self.next=self.next,(self.current+self.next)
            self.count+=1
            return self.next-self.current

    def __str__(self):
        return "Generator object"

itobj=Fib(4)
print(itobj)               #Generator object

for i in Fib(4):  
    print(i)               #0 1 1 2

print(next(itobj))         #0
print(next(itobj))         #1
print(next(itobj))         #1

6

नेड बैचेल्ड से उदाहरण और जनरेटर के लिए अत्यधिक अनुशंसित हैं

जनरेटर के बिना एक विधि जो संख्याओं के लिए भी कुछ करती है

def evens(stream):
   them = []
   for n in stream:
      if n % 2 == 0:
         them.append(n)
   return them

एक जनरेटर का उपयोग करके

def evens(stream):
    for n in stream:
        if n % 2 == 0:
            yield n
  • हमें किसी सूची या returnकथन की आवश्यकता नहीं है
  • बड़ी / अनंत लंबाई की धारा के लिए कुशल ... यह बस चलता है और मूल्य प्राप्त करता है

evensविधि (जनरेटर) को कॉल करना हमेशा की तरह है

num = [...]
for n in evens(num):
   do_smth(n)
  • जेनरेटर भी डबल लूप को तोड़ने के लिए उपयोग किया जाता है

इटरेटर

पृष्ठों से भरी एक पुस्तक एक चलने योग्य है , एक बुकमार्क एक पुनरावृत्त है

और इस बुकमार्क को स्थानांतरित करने के अलावा कुछ भी नहीं करना है next

litr = iter([1,2,3])
next(litr) ## 1
next(litr) ## 2
next(litr) ## 3
next(litr) ## StopIteration  (Exception) as we got end of the iterator

जनरेटर का उपयोग करने के लिए ... हमें एक फ़ंक्शन की आवश्यकता है

Iterator का उपयोग करने के लिए ... हमें ज़रूरत है nextऔरiter

जैसा कि कहा गया है:

एक जनरेटर फ़ंक्शन एक पुनरावृत्त वस्तु देता है

Iterator का संपूर्ण लाभ:

मेमोरी में एक तत्व को एक बार स्टोर करें


आपके पहले कोड के स्निपेट के बारे में, मैं जानना चाहता हूं कि सूची के अलावा और क्या 'आर्ग' हो सकता है?
इकरा

5

आप समान डेटा के लिए दोनों दृष्टिकोणों की तुलना कर सकते हैं:

def myGeneratorList(n):
    for i in range(n):
        yield i

def myIterableList(n):
    ll = n*[None]
    for i in range(n):
        ll[i] = i
    return ll

# Same values
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)
for i1, i2 in zip(ll1, ll2):
    print("{} {}".format(i1, i2))

# Generator can only be read once
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

# Generator can be read several times if converted into iterable
ll1 = list(myGeneratorList(10))
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

इसके अलावा, यदि आप मेमोरी फ़ुटप्रिंट की जांच करते हैं, तो जनरेटर बहुत कम मेमोरी लेता है क्योंकि उसे एक ही समय में सभी मानों को मेमोरी में स्टोर करने की आवश्यकता नहीं होती है।


1

मैं विशेष रूप से पायथन के नए शौक के लिए बहुत ही सरल तरीके से लिख रहा हूं, हालांकि पायथन नीचे बहुत सारी चीजें करता है।

बहुत मूल के साथ शुरू करते हैं:

एक सूची पर विचार करें,

l = [1,2,3]

आइए एक समान फ़ंक्शन लिखें:

def f():
    return [1,2,3]

o / p का print(l): [1,2,3]& o / p काprint(f()) : [1,2,3]

आइए बनाते हैं लिस्ट को iterable: अजगर लिस्ट में हमेशा iterable होता है यानी आप जब चाहें इटरेटर लगा सकते हैं।

आइए सूची पर पुन: लागू करें:

iter_l = iter(l) # iterator applied explicitly

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

नोट: हर जेनरेटर हमेशा लागू किए गए इटरेटर के साथ चलने योग्य होता है और यहाँ इम्परेटर इट्रिम क्रुक्स होता है इसलिए जनरेटर फंक्शन होगा:

def f():
  yield 1 
  yield 2
  yield 3

iter_f = f() # which is iter(f) as iterator is already applied implicitly

इसलिए यदि आपने देखा है, जैसे ही आपने फंक्शन एफ जनरेटर बनाया है, तो यह पहले से ही iter (f) है

अभी,

l वह सूची है, जो पुनरावृति विधि "iter" लागू करने के बाद, iter (l) बन जाती है

f पहले से ही iter है

यह थोड़े है आप इंट (एक्स) के लिए इंट कास्टिंग कर रहे हैं जो पहले से ही इंट है और यह इंट (एक्स) रहेगा।

उदाहरण के लिए ओ / पी:

print(type(iter(iter(l))))

है

<class 'list_iterator'>

यह कभी न भूलें कि यह पायथन है और C या C ++ नहीं है

इसलिए उपरोक्त स्पष्टीकरण से निष्कर्ष यह है:

सूची l ~ = iter (l)

जनरेटर फ़ंक्शन f == iter (f)

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