সংক্ষেপে, যখন কন্ট্রোল আপনার প্রোগ্রামে return স্টেটমেন্টে পৌঁছায়, প্রোগ্রামের এক্সিকিউশন টার্মিনেট হয়ে যায় এবং বাকি স্টেটমেন্টগুলো এক্সিকিউট হয় না।
তবে, yield এর ক্ষেত্রে, যখন কন্ট্রোল আপনার প্রোগ্রামে yield স্টেটমেন্টে পৌঁছায়, প্রোগ্রামের এক্সিকিউশন পজ করে এবং পরে ফাংশনের বাকি স্টেটমেন্টগুলো কন্টিনিউ করতে পারি।
দুটি স্টেটমেন্টকে বিস্তারিত বুঝি।
Yield
এক ফাংশনে yield স্টেটমেন্ট ব্যবহার করলে সেটি একটি জেনারেটর ফাংশন হয়ে যায় যা লুপে ব্যবহার করা যায়। ফাংশন রান হচ্ছে এবং yield স্টেটমেন্ট এক্সিকিউট হলে, yield-এর পরের মান সেটি কল করা লুপে ফিরে যাবে। লুপ পরবর্তীবার ইটারেট করলে, ফাংশন yield স্টেটমেন্টের ঠিক পর থেকে শুরু হবে।
def func():
yield 1
yield 2
yield 3
for num in func():
print(num * num)
আউটপুট
1 4 9
উপরের প্রোগ্রামে, ফাংশন আহ্বানকারী লুপটি তখন কমপ্লিট হবে যখন func ফাংশন কমপ্লিট হবে — либо ফাংশনের শেষে (func()) অথবা একটি return স্টেটমেন্টে।
তবে, একই জেনারেটর ফাংশন ব্যবহার করে যে কোনো নতুন লুপ চালালে, ফাংশন আবার শুরু থেকে এক্সিকিউট হবে।
Return
একটি return স্টেটমেন্ট:
- ফাংশনের এক্সিকিউশন বন্ধ করে এবং অপশনালি কলারের কাছে একটি মান রিটার্ন করে। যেই ফাংশনে
returnআছে (কিন্তুyieldনেই) সেটি লুপে ব্যবহার করা যায় না (উপরেরyield-এর মতো)। - যদি আগে এক্সিকিউট করা ফাংশনটি আবার কল করা হয়, তবে ফাংশন শুরু থেকে এক্সিকিউশন শুরু করে (উপরের
yield-এর মতো নয়)।
return বা yield কখন ব্যবহার করব?
যখন আমরা একটি সিকোয়েন্সের ওপর ইটারেট করতে চাই কিন্তু রিসোর্স কনস্ট্রেইন্ট বা পুরো সিকোয়েন্স মেমোরিতে রাখতে না চাই, তখন yield ব্যবহার করার পরামর্শ দেওয়া হয়। অন্যান্য কেসে return স্টেটমেন্ট ব্যবহার করা যেতে পারে।
নিচে yield স্টেটমেন্ট ব্যবহার করে ইন্টিজার নম্বরের স্কোয়ার জেনারেট করার আরেকটি প্রোগ্রাম দেওয়া হলো।
def Square():
i = 1
# স্কোয়ার জেনারেট করার জন্য ইনফাইনাইট লুপ
while True:
yield i * i
i += 1
# পরবর্তী এক্সিকিউশন এই পয়েন্ট থেকে রিজিউম হবে
for num in Square():
if num > 100:
break
print(num)
আউটপুট
1 4 9 16 25 36 49 64 81 100
yield স্টেটমেন্ট সাধারণত try ... finally ব্লকের try ক্লজে ব্যবহার করা হয় না, কারণ কোনো গ্যারান্টি নেই যে জেনারেটর আবার রিজিউম হবে, তাই finally ব্লক এক্সিকিউট হবে কিনা সেটাও গ্যারান্টি নেই।