পাইথনের জেনারেটর এবং আইট্রেটারগুলির মধ্যে পার্থক্য


537

পুনরুক্তি এবং জেনারেটরের মধ্যে পার্থক্য কী? আপনি যখন প্রতিটি কেস ব্যবহার করবেন তখন কয়েকটি উদাহরণ সহায়ক হবে।

উত্তর:


541

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

আপনার অ্যাপ্লিকেশনটিতে যদি এই জাতীয় অতিরিক্ত কার্যকারিতার কোনও সত্যিকারের প্রয়োজন হয়।


আমি এটির তৈরির পরে আমি কীভাবে পুনরায় ব্যবহার করব?
ভিনসেঞ্জুও

@ ভিন্সনজুও এটির সাথে আপনি কী করতে চান তার উপর নির্ভর করে। এটি হয় একটি অংশ হতে হবে for ... in ...:, একটি ফাংশন পাস, বা আপনি কল করা হবেiter.next()
ক্যালথ

@ ক্যালথ আমি সঠিক বাক্য গঠন সম্পর্কে জিজ্ঞাসা করছিলাম, কারণ for..inসিনট্যাক্সটি ব্যবহার করার চেষ্টা করার সময় আমি ত্রুটি পাচ্ছিলাম । হয়তো আমি কিছু অনুপস্থিত ছিল, তবে এটি কিছু সময় আগে, আমি সমাধান করলে মনে পড়ে না। ধন্যবাদ!
ভিনসেঞ্জুও

135

পুনরুক্তি এবং জেনারেটরের মধ্যে পার্থক্য কী? আপনি যখন প্রতিটি কেস ব্যবহার করবেন তখন কয়েকটি উদাহরণ সহায়ক হবে।

সংক্ষেপে বলা: Iterators বস্তু আছে একটি হয় __iter__এবং একটি __next__( nextপাইথন এ 2) পদ্ধতি। জেনারেটরগুলি আইট্রেটারগুলির উদাহরণ তৈরি করার জন্য একটি সহজ, অন্তর্নির্মিত উপায় সরবরাহ করে।

এতে ফলন সহ একটি ফাংশন এখনও একটি ফাংশন, যাকে বলা হয়, একটি জেনারেটরের কোনও সামগ্রীর উদাহরণ দেয়:

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'>

এবং একটি জেনারেটর, আবার, একটি আইট্রেটার:

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

কোনো ইটারেটরে হয় একটি Iterable

একজন আইট্রেটার একটি স্বচ্ছল,

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

যার জন্য এমন একটি __iter__পদ্ধতি প্রয়োজন যা একটি আইট্রেটরকে ফেরত দেয়:

>>> 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পুনরাবৃত্তি উত্থাপিত হয় যখন আপনি এটি ক্লান্ত করে ফেলেছেন এবং এটি সেই সময়ে পুনরায় ব্যবহার করা যাবে না।

ডকুমেন্টেশন থেকে

বিল্ট-ইন টাইপ ডকুমেন্টেশনের ইটারেটর প্রকার বিভাগের জেনারেটর প্রকার বিভাগ থেকে :

পাইথনের জেনারেটর পুনরায় প্রোটোকল প্রয়োগের জন্য একটি সুবিধাজনক উপায় সরবরাহ করে। যদি কোনও ধারক অবজেক্টের __iter__()পদ্ধতিটি জেনারেটর হিসাবে প্রয়োগ করা হয় তবে এটি স্বয়ংক্রিয়ভাবে একটি পুনরাবৃত্ত বস্তু (প্রযুক্তিগতভাবে, একটি জেনারেটর বস্তু) সরবরাহ করবে __iter__()এবং next()[ __next__()পাইথন 3 ইন] পদ্ধতিগুলি সরবরাহ করবে। জেনারেটর সম্পর্কে আরও তথ্য ফলন প্রকাশের ডকুমেন্টেশনে পাওয়া যায়।

(সামনে জোর দাও.)

সুতরাং এটি থেকে আমরা জানতে পারি যে জেনারেটর হ'ল (সুবিধাজনক) ধরণের আইট্রেটার।

উদাহরণস্বরূপ আইট্রেটর অবজেক্টস

আপনি নিজের অবজেক্ট তৈরি বা প্রসারিত করে আইটেটর প্রোটোকল প্রয়োগ করে এমন বস্তু তৈরি করতে পারেন।

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কোনও জেনারেটর ইটারেটর ফিরিয়ে দেয় বা জেনারেটর এক্সপ্রেশন বিবেচনা করে এমন ফাংশনটি সংজ্ঞায়িত করতে আপনি সবচেয়ে উপযুক্ত suited

পরিশেষে, নোট করুন যে জেনারেটরগুলি কর্টাইন হিসাবে আরও বেশি কার্যকারিতা সরবরাহ করে। আমি জেনারেটরদের 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
শুধু এফওয়াইআই ফলন পদ্ধতি নয়, মূল শব্দটি
জয় পরখ

25

একটি উত্তর যুক্ত করা হচ্ছে কারণ বিদ্যমান উত্তরগুলির কোনওটিই বিশেষভাবে সরকারী সাহিত্যের বিভ্রান্তির সমাধান করে না।

জেনারেটর ফাংশনগুলি এরyieldপরিবর্তেব্যবহার করে সংজ্ঞায়িত করা সাধারণ ফাংশনreturn। যখন ডাকা হয়, একটি জেনারেটর ফাংশন একটি জেনারেটর অবজেক্ট ফিরিয়ে দেয়, যা এক ধরণের পুনরুত্পাদনকারী - এটির একটিnext()পদ্ধতি রয়েছে। আপনি যখন কল করবেন তখনnext()জেনারেটর ফাংশন দ্বারা প্রাপ্ত পরবর্তী মানটি ফিরে আসবে।

আপনি পাইথন উত্স নথিটি পড়েছেন তার উপর নির্ভর করে ফাংশন বা অবজেক্টটিকে "জেনারেটর" বলা যেতে পারে। পাইথন শব্দকোষ জেনারেটরের ফাংশন বলছেন, যখন পাইথন উইকি জেনারেটরের বস্তু বোঝা। পাইথন টিউটোরিয়াল সাতিশয় পরোক্ষভাবে পরিচালনা করে উভয় তিন বাক্যের স্থান রীতিনীতি:

জেনারেটর পুনরুক্তি তৈরির জন্য একটি সহজ এবং শক্তিশালী সরঞ্জাম। এগুলি নিয়মিত ফাংশনের মতো লেখা হয় তবে যখনই তারা ডেটা ফিরিয়ে দিতে চায় ফলন বিবরণী ব্যবহার করে। এর পরের বার () এর উপরে কল করা হলে, জেনারেটরটি যেখানেই ছেড়েছিল সেগুলি আবার শুরু করে (এটি সমস্ত ডেটা মানগুলি স্মরণ করে এবং কোন বিবৃতি সর্বশেষ কার্যকর করা হয়েছিল)।

প্রথম দুটি বাক্য জেনারেটর ফাংশন সহ জেনারেটরগুলি সনাক্ত করে, তৃতীয় বাক্যটি জেনারেটরের সাথে তাদের সনাক্ত করে।

এই সমস্ত বিভ্রান্তির পরেও, পরিষ্কার ও চূড়ান্ত শব্দের জন্য পাইথন ভাষার রেফারেন্সটি খুঁজে পেতে পারেন :

উত্পাদনের এক্সপ্রেশনটি কেবলমাত্র জেনারেটরের ফাংশন সংজ্ঞায়িত করার সময় ব্যবহৃত হয় এবং কেবলমাত্র কোনও ফাংশন সংজ্ঞাতে শরীরে ব্যবহার করা যেতে পারে। কোনও ফাংশন সংজ্ঞায় একটি ফলন প্রকাশটি ব্যবহার করা সেই সংজ্ঞাটিকে সাধারণ ফাংশনের পরিবর্তে জেনারেটর ফাংশন তৈরি করতে যথেষ্ট।

যখন কোনও জেনারেটরের ফাংশন বলা হয়, এটি একটি জেনারেটর হিসাবে পরিচিত একটি পুনরাবৃত্তিকে ফিরিয়ে দেয়। সেই জেনারেটর তারপরে একটি জেনারেটরের ফাংশন কার্যকর করে।

সুতরাং, আনুষ্ঠানিক এবং নির্ভুল ব্যবহারে, "জেনারেটর" অযোগ্য অর্থ জেনারেটরের কাজ নয়, জেনারেটরের কাজ নয়।

উপরোক্ত রেফারেন্সগুলি পাইথন 2 এর জন্য তবে পাইথন 3 ভাষার রেফারেন্স একই কথা বলে। যাইহোক, পাইথন 3 গ্লোসারিটিতে বলা হয়েছে

জেনারেটর ... সাধারণত একটি জেনারেটর ফাংশন বোঝায়, তবে কিছু প্রসঙ্গে একটি জেনারেটরের পুনরায় উল্লেখ করতে পারে। যে ক্ষেত্রে উদ্দিষ্ট অর্থ পরিষ্কার নয়, সম্পূর্ণ পদ ব্যবহার করে অস্পষ্টতা এড়ানো যায়।


আমি মনে করি না জেনারেটর ফাংশন এবং জেনারেটর অবজেক্টগুলির মধ্যে খুব একটা বিভ্রান্তি রয়েছে, একই কারণে সাধারণত ক্লাস এবং তাদের দৃষ্টান্তগুলির মধ্যে কোনও বিভ্রান্তি নেই। উভয় ক্ষেত্রেই, আপনি অন্যটিকে পেতে একজনকে কল করেন এবং নৈমিত্তিক কথোপকথনে (বা দ্রুত লিখিত ডকুমেন্টেশন) আপনি কোনও একটির জন্য শ্রেণীর নাম বা "জেনারেটর" শব্দটি ব্যবহার করতে পারেন। বিরল পরিস্থিতিতে যেখানে আপনি বিষয়গুলির বিষয়ে কথা বলছেন সেখানে আপনাকে কেবল "জেনারেটর ফাংশন" বনাম "জেনারেটর অবজেক্ট" সম্পর্কে স্পষ্ট হওয়া দরকার।
ব্ল্যাককিংহাট

6
1. কেন বিভ্রান্তি হওয়া উচিত না এর তাত্ত্বিক কারণ নির্বিশেষে, এই প্রশ্নের অন্যান্য উত্তরের মন্তব্যগুলি সমাধান ছাড়াই একে অপরকে অস্বীকার করে এবং বিরোধিতা করে, প্রকৃত বিভ্রান্তির উপস্থিতি নির্দেশ করে। ২. নৈমিত্তিক অসম্পূর্ণতা ঠিক আছে তবে একটি সুনির্দিষ্ট, প্রামাণিক উত্স কমপক্ষে এসও-র বিকল্পগুলির মধ্যে একটি হওয়া উচিত। আমি আমার বর্তমান প্রকল্পে জেনারেটর ফাংশন এবং অবজেক্ট উভয়ই ব্যবহার করি এবং ডিজাইন এবং কোডিংয়ের সময় পার্থক্যটি খুব গুরুত্বপূর্ণ। এখন কোন পরিভাষাটি ব্যবহার করবেন তা জেনে রাখা ভাল, সুতরাং আমাকে কয়েক ডজন পরিবর্তনশীল নাম এবং মন্তব্যগুলি পরে পরিবর্তন করতে হবে না।
পল

2
এমন একটি গণিতের সাহিত্যের কল্পনা করুন যেখানে কোনও ফাংশন এবং তার ফেরতের মূল্যের মধ্যে কোনও পার্থক্য তৈরি হয় না। এগুলি অনানুষ্ঠানিকভাবে আবদ্ধ করা মাঝে মধ্যে সুবিধাজনক তবে এটি বিভিন্ন ধরণের ভুল হওয়ার ঝুঁকি বাড়িয়ে তোলে। উন্নত আধুনিক গণিত উল্লেখযোগ্য এবং অযথা বাধা হয়ে দাঁড়াবে যদি পার্থক্যটি কনভেনশন, ভাষা এবং স্বীকৃতিতে আনুষ্ঠানিকভাবে না করা হয়।
পল

2
জেনারেটর বা জেনারেটরের ফাংশনগুলির চারপাশে পাস করা উচ্চ-অর্ডার ফাংশনগুলি অদ্ভুত শোনাতে পারে তবে আমার জন্য তারা আসছে। আমি অ্যাপাচি স্পার্কে কাজ করছি এবং এটি একটি খুব কার্যকরী প্রোগ্রামিং শৈলী প্রয়োগ করে। ফাংশনগুলিকে জিনিসগুলি তৈরি করতে সমস্ত ধরণের বস্তু তৈরি করতে, প্রবেশ করতে এবং আউট করতে হয়। আমি বেশ কয়েকটি পরিস্থিতি পেয়েছি যেখানে আমি কী ধরণের "জেনারেটর" এর সাথে কাজ করছি তার ট্র্যাক হারিয়েছি। সামঞ্জস্যপূর্ণ এবং সঠিক পরিভাষা ব্যবহার করে চলক নাম এবং মন্তব্যে ইঙ্গিতগুলি বিভ্রান্তি দূর করতে সহায়তা করে। একজন পাইথনিস্টের অস্পষ্টতা অন্যের প্রকল্প ডিজাইনের কেন্দ্র হতে পারে!
পল

1
@ পল, এই উত্তরটি লেখার জন্য ধন্যবাদ। এই বিভ্রান্তি গুরুত্বপূর্ণ কারণ একটি জেনারেটর অবজেক্ট এবং জেনারেটরের ফাংশনের মধ্যে পার্থক্য হ'ল কাঙ্ক্ষিত আচরণ এবং জেনারেটর অনুসন্ধানের মধ্যে পার্থক্য।
blujay

16

প্রত্যেকের উদাহরণ সহ একটি দুর্দান্ত এবং ভার্জিক উত্তর রয়েছে এবং আমি সত্যিই এটির প্রশংসা করি। আমি কেবলমাত্র এমন লোকদের জন্য একটি সংক্ষিপ্ত কয়েকটি লাইনের উত্তর দিতে চেয়েছিলাম যারা এখনও ধারণাগতভাবে যথেষ্ট পরিষ্কার নয়:

আপনি যদি নিজের আইটিরেটর তৈরি করেন তবে এটি কিছুটা জড়িত - আপনাকে একটি শ্রেণী তৈরি করতে হবে এবং কমপক্ষে ইটার এবং পরবর্তী পদ্ধতিগুলি প্রয়োগ করতে হবে। তবে আপনি যদি এই ঝামেলাটি অতিক্রম করতে না চান এবং দ্রুত একটি পুনরুক্তি তৈরি করতে চান তবে কী হয়। ভাগ্যক্রমে, পাইথন একটি পুনরুক্তি নির্ধারণের জন্য একটি শর্ট-কাট উপায় সরবরাহ করে provides আপনাকে যা করতে হবে তা হ'ল উত্পাদনের জন্য কমপক্ষে 1 টি কল দিয়ে একটি ফাংশন সংজ্ঞায়িত করা হবে এবং এখন আপনি যখন সেই ফাংশনটি কল করবেন তখন এটি " কিছু " ফিরে আসবে যা একটি পুনরুক্তির মতো কাজ করবে (আপনি পরবর্তী পদ্ধতিতে কল করতে পারেন এবং এটি লুপের জন্য ব্যবহার করতে পারেন)। পাইথনের এই জিনিসের একটি নাম রয়েছে জেনারেটর

আশা করি কিছুটা স্পষ্ট হয়ে যায়।


9

পূর্ববর্তী উত্তরগুলি এই সংযোজনটি মিস করেছে: একটি জেনারেটরের একটি closeপদ্ধতি রয়েছে, তবে সাধারণ পুনরাবৃত্তিকারীরা তা করেন না। closeপদ্ধতি আরম্ভ করে StopIterationজেনারেটরের মধ্যে ব্যতিক্রম, যা একটি ধরা হতে পারেfinally যে পুনরুক্তিকারীর মধ্যে দফা, কিছু ক্লিন-আপ চালানোর জন্য একটি সুযোগ পেতে। এই বিমূর্ততাটি সাধারণ পুনরাবৃত্তির চেয়ে বৃহত্তর ক্ষেত্রে এটি সবচেয়ে ব্যবহারযোগ্য করে তোলে। যে কোনও জেনারেটর বন্ধ করতে পারে যেহেতু কোনও ফাইল বন্ধ করতে পারে, নীচের বিষয়গুলি নিয়ে উদ্বিগ্ন না করে।

এটি বলেছিল, প্রথম প্রশ্নের আমার ব্যক্তিগত উত্তরটি হবে: পুনরাবৃত্তির একটি __iter__পদ্ধতি কেবল আছে, সাধারণ পুনরাবৃত্তির একটি থাকে__next__ পদ্ধতি কেবল থাকে, জেনারেটরের একটি __iter__এবং একটি __next__এবং অতিরিক্ত উভয় থাকে close

দ্বিতীয় প্রশ্নের জন্য, আমার ব্যক্তিগত উত্তরটি হবে: একটি পাবলিক ইন্টারফেসে, আমি জেনারেটরগুলিকে অনেক বেশি পক্ষপাতী করি, যেহেতু এটি আরও স্থিতিস্থাপক: closeপদ্ধতিটি একটি বৃহত্তর সংশ্লেষের সাথেyield from । স্থানীয়ভাবে, আমি পুনরাবৃত্তকারীগুলি ব্যবহার করতে পারি, তবে কেবল যদি এটি সমতল এবং সাধারণ কাঠামো হয় (পুনরাবৃত্তিকারীরা সহজেই রচনা করে না) এবং যদি বিশ্বাস করার কোনও কারণ থাকে তবে ক্রমটি সংক্ষিপ্ততরটি খুব কম হলেও বিশেষত এটি শেষ হওয়ার আগেই বন্ধ হয়ে যেতে পারে। আমি পুনরাবৃত্তিকে আক্ষরিক হিসাবে বাদ দিয়ে নিম্ন স্তরের আদিম হিসাবে দেখি।

নিয়ন্ত্রণ প্রবাহের বিষয়গুলির জন্য, জেনারেটরগুলি প্রতিশ্রুতির মতোই একটি গুরুত্বপূর্ণ ধারণা: উভয়ই বিমূর্ত এবং কম্পোজেবল।


রচনা সম্পর্কে কথা বলার সময় আপনি বোঝানোর জন্য উদাহরণ দিতে পারেন? এছাড়াও, " সাধারণ পুনরাবৃত্তি" সম্পর্কে কথা বলার সময় আপনি কী মনে রেখেছেন তা ব্যাখ্যা করতে পারেন ?
bli

1
অন্য একটি উত্তর ( স্ট্যাকওভারফ্লো.com / a / 28353158 / 1878788 ) বলেছেন যে "একটি পুনরাবৃত্তি একটি পুনরাবৃত্তিযোগ্য"। যেহেতু একটি পুনরাবৃত্তের একটি __iter__পদ্ধতি থাকে, কেবল পুনরাবৃত্তির কীভাবে আসতে পারে __next__? যদি তাদের পুনরাবৃত্তিযোগ্য বলে মনে করা হয়, তবে আমি অবশ্যই তাদের প্রয়োজনীয়তা অর্জনের প্রত্যাশা করব __iter__
bli

1
@ ব্লি: এএএফআইএসস এই উত্তরটি এখানে স্ট্যান্ডার্ড পিইপি 234 বোঝায় , সুতরাং এটি সঠিক, অন্য উত্তরটি কিছু বাস্তবায়নকে বোঝায় তাই এটি প্রশ্নবিদ্ধ। স্ট্যান্ডার্ডটির কেবল একটি __iter__পুনরাবৃত্তিকে ফিরিয়ে আনতে কেবল পুনরায় পুনরায় চলন প্রয়োজন, যা কেবলমাত্র একটি nextপদ্ধতি ( __next__পাইথন 3 এ) প্রয়োজন। দয়া করে মান প্রয়োগগুলি (হাঁসের টাইপিংয়ের জন্য) তাদের বাস্তবায়নের সাথে বিভ্রান্ত করবেন না (কোনও নির্দিষ্ট পাইথন দোভাষী কীভাবে এটি প্রয়োগ করেছেন)। এটি কিছুটা জেনারেটর ফাংশন (সংজ্ঞা) এবং জেনারেটর অবজেক্টস (বাস্তবায়ন) এর মধ্যে বিভ্রান্তির মতো। ;)
টিনো

7

জেনারেটর ফাংশন, জেনারেটর অবজেক্ট, জেনারেটর:

একটি জেনারেটর ফাংশন শুধু পাইথন মধ্যে একজন নিয়মিত ফাংশন মত কিন্তু এটা এক বা একাধিক রয়েছে yieldবিবৃতি। জেনারেটর ফাংশনগুলি আইট্রেটার অবজেক্টগুলি যথাসম্ভব সহজতর করার একটি দুর্দান্ত সরঞ্জাম । ইটারেটর জেনারেটরের ফাংশন দ্বারা বস্তুর 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

সুতরাং একটি জেনারেটর ফাংশন হ'ল একটি ইট্রেটর অবজেক্ট তৈরির সহজতম উপায়।

আইট্রেটার :

প্রতিটি জেনারেটর অবজেক্ট একটি পুনরাবৃত্তি হয় তবে বিপরীতে নয়। এর শ্রেণি প্রয়োগ __iter__এবং __next__পদ্ধতি (এটিরেটর প্রোটোকল নামে পরিচিত) যদি একটি কাস্টম পুনরাবৃত্তকারী অবজেক্ট তৈরি করা যায় ।

তবে, পুনরুক্তি তৈরির জন্য জেনারেটর ফাংশন ব্যবহার করা অনেক সহজ কারণ তারা তাদের নির্মাণকে সহজ করে তোলে তবে একটি কাস্টম আইট্রেটর আপনাকে আরও বেশি স্বাধীনতা দেয় এবং নীচের উদাহরণে প্রদর্শিত আপনার প্রয়োজন অনুসারে আপনি অন্যান্য পদ্ধতিও প্রয়োগ করতে পারেন।

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)
  • জেনারেটরও ডাবল লুপ ভাঙত

iterator

পুস্তক পৃষ্ঠাগুলির পূর্ণ একটি হল iterable , একটি বুকমার্ক একটি হল পুনরুক্তিকারীর

এবং এই বুকমার্কটির সরানো ছাড়া কিছুই করার নেই 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

যেমন বলা হয়েছে:

একটি জেনারেটর ফাংশন একটি পুনরুক্তিযোগ্য বস্তু প্রদান করে

আইট্রেটারের পুরো সুবিধা:

একটি উপাদান স্মৃতিতে একটি সময় সঞ্চয় করুন


আপনার প্রথম কোড স্নিপেট সম্পর্কে, আমি জানতে চাই যে 'আর স্ট্রিম' তালিকার চেয়ে আর কী হতে পারে?
ইকরা।

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]

ও / পি এর print(l): [1,2,3]& ও / পি এরprint(f()) : [1,2,3]

আসুন তালিকাটি পুনরাবৃত্তযোগ্য করে তুলুন: পাইথন তালিকায় সর্বদা পুনরাবৃত্ত হয় এর অর্থ আপনি যখনই চান পুনরাবৃত্তিকে প্রয়োগ করতে পারেন।

আসুন তালিকায় পুনরাবৃত্তি প্রয়োগ করুন:

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

সুতরাং আপনি যদি পর্যবেক্ষণ করেছেন, ফাংশন এফ জেনারেটর তৈরি করার সাথে সাথেই এটি ইতিমধ্যে ইটার (চ)

এখন,

l হল তালিকা, পুনরাবৃত্ত পদ্ধতি প্রয়োগ করার পরে "ইটার" এটি হয়ে যায়, ইটার (l)

চ ইতিমধ্যে ইটার (চ) রয়েছে, পুনরাবৃত্ত পদ্ধতি প্রয়োগ করার পরে "ইটার" এটি হয়ে যায়, ইটার (ইটার (চ)), যা আবার ইটার (চ) হয়

এটি এমন কি আপনি ইতিপূর্বে ইন্ট (এক্স) এর জন্য castালাই করছেন যা ইতিমধ্যে অন্তর্নিহিত এবং এটি ইনট (এক্স) থাকবে।

উদাহরণস্বরূপ ও / পি:

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

হয়

<class 'list_iterator'>

এটি পাইথন এবং সি বা সি ++ নয় কখনও ভুলে যাবেন না

সুতরাং উপরোক্ত ব্যাখ্যা থেকে উপসংহারটি হ'ল:

তালিকা l ~ = ইটার (l)

জেনারেটর ফাংশন f == ইটার (চ)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.