কম্পিউটার টিউটোরিয়াল

পাইথনে জেনারেটর (Generators)


জেনারেটর পাইথনে একটি গুরুত্বপূর্ণ অংশ যেকোনো সময় থেকে যাবতীয় রয়েছে যেহেতু এগুলো PEP 255-এ পরিচয় করানো হয়েছিল।

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

যেকোনো পাইথন ফাংশন যেটিতে "yield" কীওয়ার্ড থাকে, সেটিকে জেনারেটর বলা যায়। একটি নরমাল পাইথন ফাংশন প্রথম লাইন থেকে এক্সিকিউশন শুরু করে এবং রিটার্ন স্টেটমেন্ট বা এক্সসেপশন বা ফাংশনের শেষ পর্যন্ত চালিয়ে যায়, তবে ফাংশন স্কোপের время তৈরি হওয়া যেকোনো লোকাল ভেরিয়েবল নষ্ট হয়ে যায় এবং পরে অ্যাক্সেসযোগ্য নয়। কিন্তু জেনারেটরের ক্ষেত্রে যখন yield কীওয়ার্ড মільে, ফাংশনের স্টেট ফ্রোজ হয়ে যায় এবং সব ভেরিয়েবল মেমরিতে সংরক্ষিত থাকে যতক্ষণ না জেনারেটর আবার কল করা হয়।

আমরা জেনারেটরকে একটি ইটেরেটর সাথে ব্যবহার করতে পারি বা স্পষ্টভাবে "next" কীওয়ার্ড ব্যবহার করে কল করতে পারি।

সাধারণত পাইথনে জেনারেটর:

  • def কীওয়ার্ড দিয়ে ডিফাইন করা হয়
  • yield কীওয়ার্ড ব্যবহার করে
  • অনেকগুলো yield কীওয়ার্ড থাকতে পারে
  • একটি ইটেরেটর রিটার্ন করে

ইটেরেটরসহ জেনারেটর

def generator_thr_iter():
    yield 'xyz'
    yield 246
    yield 40.50

for i in generator_thr_iter():
    print(i)

আউটপুট

xyz
246
40.5

next ব্যবহার করে জেনারেটর

def generator_thr_iter():
    yield 'xyz'
    yield 246
    yield 40.50

>>> g = generator_thr_iter()
>>> g.__next__()
'xyz'
>>> g.__next__()
246
>>> g.__next__()
40.5
>>> g.__next__()
Traceback (most recent call last):
File "", line 1, in 
g.__next__()
StopIteration

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

১ থেকে n পর্যন্ত সংখ্যার বর্গ প্রিন্ট করার প্রোগ্রাম

বিবেচনা করুন আমরা ১ থেকে n পর্যন্ত সংখ্যার বর্গ ক্যালকুলেট করতে চাই, যেখানে n খুব বড় একটি সংখ্যা, যেন n পর্যন্ত সংখ্যার লিস্ট তৈরি করলে পুরো সিস্টেম মেমরি স্পেস অক্যুপাই করবে।

জেনারেটর ছাড়া, আমাদের পদ্ধতি হবে কিছু এইভাবে:

>>> n = 200000000000
>>> number_list = range(1, n+1)
>>> for i in number_list:
    print(i*i)

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

একই কাজের জন্য আমাদের জেনারেটর প্রোগ্রাম হবে:

def num_generator(n):
    num = 1
    while True:
        yield num
        if num == n:
            return
        else:
            num += 1

for i in num_generator(200000000000):
    print(i*i)

উপরের পদ্ধতিতে, যখন for লুপ প্রথমে ইনিশিয়ালাইজ হয়, num_generator কল হয় এবং n = 200000000000 এর মান মেমরিতে সংরক্ষিত হয় এবং num=1 ইনিশিয়ালাইজ হয় এবং হয়ে যায় while লুপে যা চিরকাল লুপ করবে। তারপর yield num এনকাউন্টার হয়, এই সময় while লুপ ফ্রোজ হয়ে যায় এবং সব লোকাল ভেরিয়েবল মেমরিতে সংরক্ষিত থাকে। যেহেতু num=1, yield num for লুপে রিটার্ন হয় এবং i-তে অ্যাসাইন হয়, যেখানে 1 (i*i) প্রিন্ট হয় এবং num_generator-কে পরবর্তী কল করা হয়।

এখন এক্সিকিউশন সেখানে থেকে শুরু হয় যেখানে এটি পূর্বে ফ্রোজ হয়েছিল, তাই এটি লাইন num == n (1 == 200000000000) এক্সিকিউট করে, যা false, তাই num +=1 এক্সিকিউট হয় যা num = 2-এ আসে এবং while লুপ আবার এক্সিকিউট হয় এবং প্রক্রিয়া চালিয়ে যায়।

শেষ পর্যন্ত while লুপ এক্সিকিউট হয় n=200000000000 পর্যন্ত, যখন 200000000000 yield করা হয়, তারপর নেক্সট লাইন 'num == n' (200000000000 == 200000000000) এক্সিকিউট হয়, যেহেতু এটি true, রিটার্ন স্টেটমেন্ট এক্সিকিউট হয়।

সুতরাং যখন জেনারেটর একটি রিটার্ন স্টেটমেন্ট এক্সিকিউট করে বা এক্সসেপশন এনকাউন্টার করে বা জেনারেটরের শেষে পৌঁছায়, "StopIteration" এক্সসেপশন রেইজ হয় এবং for লুপ ইটেরেশন ওই মুহূর্তে থামে। তাই উপরে আমরা ২০০০০০০০০০০০ পর্যন্ত সংখ্যার বর্গ প্রিন্ট করতে পেরেছি কখনো বড় সংখ্যার লিস্ট তৈরি না করেও যা বড় সিস্টেম মেমরি অক্যুপাই করত।

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


  1. পাইথন জেনারেটর লেখার পদ্ধতি

  2. পাইথন yield কিওয়ার্ড: একটি গাইড

  3. জাভাস্ক্রিপ্ট জেনারেটর ফাংশন

  4. পাইথনে issuperset() ফাংশন