এই অংশে আপনি যে প্রতিটি for লুপ লিখেছেন তা একটি প্রক্রিয়ার উপর নির্ভর করেছে যা সরাসরি বোঝার মতো: Python-এর ইটারেটর প্রোটোকল। একটি জেনারেটর নিজের একটি তৈরি করার একটি সহজ, সাধারণ উপায়।
লিস্ট, tuple, ডিকশনারি, আর স্ট্রিং সবগুলোই iterable — for x in ... এদের সবার উপর কাজ করে কারণ প্রতিটি জানে জিজ্ঞাসা করা হলে ভেতরে ভেতরে iter() আর next()-এর মাধ্যমে একবারে একটি করে আইটেম কীভাবে তৈরি করতে হয়:
numbers = [1, 2, 3]
iterator = iter(numbers)
print(next(iterator)) # 1
print(next(iterator)) # 2
print(next(iterator)) # 3
# next(iterator) # StopIteration — nothing leftএকটি for লুপ আসলে এই প্যাটার্নটাই, সুবিধাজনক সিনট্যাক্সে মোড়ানো — এটি শেষ না হওয়া পর্যন্ত বারবার next() কল করে।
একবার লুপ করার জন্য একটি সম্পূর্ণ লিস্ট তৈরি করা মেমরি অপচয় করে যদি লিস্টটি বিশাল হয়, বা অসম্ভব যদি এটি অসীম হয়। একটি জেনারেটর ফাংশন — return-এর বদলে yield ব্যবহার করে — একবারে সম্পূর্ণ ক্রম মেমরিতে না রেখেই, চাহিদা অনুযায়ী একবারে একটি করে মান তৈরি করে:
def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1
for number in count_up_to(5):
print(number) # 1, 2, 3, 4, 5 — computed one at a time, not built as a list firstএকটি জেনারেটর এক্সপ্রেশন এই অংশের আগের দিকের list comprehension-এর lazy কাজিন — স্কয়ার ব্র্যাকেটের বদলে বন্ধনী ব্যবহার করুন:
squares_list = [n ** 2 for n in range(1000000)] # builds all million values right now
squares_gen = (n ** 2 for n in range(1000000)) # builds nothing yet — values come one at a timeলিস্ট বনাম জেনারেটর — কখন কোনটা যুক্তিসঙ্গত
ডেটার উপর একাধিকবার লুপ করতে হলে, দৈর্ঘ্য চেক করতে হলে, বা এতে ইনডেক্স করতে হলে একটি লিস্ট ব্যবহার করুন। একটি বড় বা open-ended ক্রম একবারে, ক্রম অনুযায়ী প্রসেস করার সময় একটি জেনারেটরের দিকে যান — একটি বিশাল ফাইল লাইন বাই লাইন পড়া একটি ধ্রুপদী বাস্তব-জগতের উদাহরণ।