অধ্যায় 11

for লুপ আর range — নির্দিষ্ট সংখ্যক বার চলা

কতবার চলবে জানা থাকলে for লুপই সঠিক পছন্দ। range-এর তিনটি রূপ, শেষ সীমা কেন বাদ যায়, আর for না while — কোনটা কখন।

35 মিনিটPython 3.12
  1. 1সমস্যা
  2. 2বোঝা
  3. 3উদাহরণ
  4. 4অনুমান
  5. 5নিজে করা
  6. 6কঠিন করা

যে সমস্যাটা আমরা সমাধান করছি

আগের মিশনে ১ থেকে ৫-এর যোগফল বের করতে আমাদের চারটে লাইন লাগল, আর তার মধ্যে দুটো ছিল শুধু হিসাব রাখার জন্য — শুরুর মান আর এক করে বাড়ানো। ওই বাড়ানোর লাইনটা ভুলে গেলেই অসীম লুপ।

কিন্তু খেয়াল করুন, এই ধরনের কাজে কতবার চলবে তা আমরা আগেই জানি। পাঁচবার। এমন ক্ষেত্রে হিসাব রাখার দায়িত্ব নিজের কাঁধে নেওয়ার কোনো দরকার নেই — পাইথনকে দিয়ে দিলেই হয়।

for লুপ ঠিক সেটাই করে। আর যেহেতু গোনার কাজটা আপনার হাতে থাকে না, for লুপ কখনো অসীম হয় না — এটাই এর সবচেয়ে বড় সুবিধা।

এই মিশন শেষে আপনি পারবেন

  • for লুপ দিয়ে নির্দিষ্ট সংখ্যক বার কোড চালাতে
  • range()-এর তিনটি রূপ ব্যবহার করতে
  • বলতে কেন range(1, 5) চারটি সংখ্যা দেয়, পাঁচটি নয়
  • লেখার প্রতিটি অক্ষরের উপর লুপ চালাতে
  • for না while — কোন কাজে কোনটা, সেই সিদ্ধান্ত নিতে

আগে যা জানা লাগবে: while লুপ — শর্ত সত্য থাকা পর্যন্ত চলা।


সবচেয়ে সহজ রূপ

python
for number in range(5):
    print(number)
text
0
1
2
3
4

তিন লাইনের কাজ এক লাইনে, আর কোনো কাউন্টার নিজে সামলাতে হয়নি। পড়তে হয় এভাবে: "`range(5)` যে সংখ্যাগুলো দেয়, তাদের প্রতিটির জন্য একবার করে ব্লকটা চালাও — আর প্রতিবার সেই সংখ্যাটা `number`-এ রাখো।"

দুটো জিনিস প্রথমেই চোখে পড়ে:

শুরু হয় শূন্য থেকে, আর 5 আসে না — মোট পাঁচটি সংখ্যা, কিন্তু 0 থেকে 4। এটাই পাইথনের সর্বত্র একই নিয়ম: স্লাইসে যেমন শেষ সীমা বাদ যায়, range-এও তাই।

number নামটা আপনার পছন্দ। for i in range(5) লেখাও চলে, আর গণনার জন্য i লেখা প্রচলিত রীতি। কিন্তু সংখ্যাটার যদি একটা অর্থ থাকে, নাম দিন সেই অর্থে — for student_number in range(30) পড়েই বোঝা যায়।

range()-এর তিনটি রূপ

python
print("--- range(5) ---")
for i in range(5):
    print(i, end=" ")

print()
print("--- range(2, 6) ---")
for i in range(2, 6):
    print(i, end=" ")

print()
print("--- range(0, 10, 3) ---")
for i in range(0, 10, 3):
    print(i, end=" ")

print()
print("--- range(5, 0, -1) ---")
for i in range(5, 0, -1):
    print(i, end=" ")
print()
text
--- range(5) ---
0 1 2 3 4
--- range(2, 6) ---
2 3 4 5
--- range(0, 10, 3) ---
0 3 6 9
--- range(5, 0, -1) ---
5 4 3 2 1

নিয়মগুলো:

  • range(stop) — 0 থেকে শুরু, stop-এর আগে শেষ
  • range(start, stop) — start থেকে শুরু, stop-এর আগে শেষ
  • range(start, stop, step) — প্রতিবার step করে এগোয়; step ঋণাত্মক হলে পিছনের দিকে

শেষ দুটো একবার মিলিয়ে দেখুন। range(0, 10, 3) দেয় 0 3 6 9 — পরের হত 12, কিন্তু সেটা 10 ছাড়িয়ে যায়, তাই থামে। আর range(5, 0, -1) দেয় 5 4 3 2 1 — 0 আসে না, কারণ শেষ সীমা এখানেও বাদ।

কেন শেষ সীমা বাদ যায়? কারণ এতে হিসাব সহজ হয়। range(0, 5)-এ সংখ্যা কতটা? 5 - 0, অর্থাৎ পাঁচটা। range(3, 8)-এ? 8 - 3, পাঁচটা। বিয়োগ করলেই সংখ্যাটা পাওয়া যায়, কোনো "এক যোগ করতে হবে কি" নিয়ে ভাবতে হয় না। আর দুটো range পাশাপাশি বসালে — range(0, 5) আর range(5, 10) — কিছুই বাদ পড়ে না, কিছুই দুবার আসে না।

এক থেকে দশ পর্যন্ত চাইলে

এই ভুলটা এতবার হয় যে আলাদা করে বলা দরকার:

python
print("Wrong — stops at 9:")
for i in range(1, 10):
    print(i, end=" ")

print()
print("Right — includes 10:")
for i in range(1, 11):
    print(i, end=" ")
print()
text
Wrong — stops at 9:
1 2 3 4 5 6 7 8 9
Right — includes 10:
1 2 3 4 5 6 7 8 9 10

নিয়মটা এক লাইনে: শেষ যে সংখ্যাটা চান, stop-এ তার এক বেশি লিখুন।

যোগফল জমানো — এবার সহজে

python
total = 0

for number in range(1, 6):
    total = total + number

print("Sum of 1 to 5:", total)
text
Sum of 1 to 5: 15

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

লেখার উপর লুপ

for শুধু সংখ্যার উপর চলে না — লেখার উপরেও চলে, অক্ষর ধরে ধরে:

python
word = "Python"

for letter in word:
    print(letter, end="-")
print()

vowel_count = 0
for letter in "programming":
    if letter in "aeiou":
        vowel_count = vowel_count + 1

print("Vowels:", vowel_count)
text
P-y-t-h-o-n-
Vowels: 3

এখানে range নেই, কারণ দরকারই নেই — for letter in word সোজা অক্ষরগুলোর উপর ঘোরে। ইনডেক্স নিয়ে হিসাব করার চেয়ে এটা সহজ, আর IndexError-এর সম্ভাবনাও থাকে না।

সংখ্যা আর অক্ষর — দুটোই একসাথে দরকার হলে enumerate() আছে, কিন্তু সেটা লিস্টের মিশনের বিষয়।

break আর continue এখানেও চলে

while-এ যেভাবে কাজ করত, ঠিক সেভাবেই:

python
for number in range(1, 20):
    if number % 7 == 0:
        print("First multiple of 7:", number)
        break
text
First multiple of 7: 7

for না while — সিদ্ধান্তটা কীভাবে নেবেন

একটাই প্রশ্ন করুন: কতবার চলবে, সেটা লুপ শুরুর আগেই জানা আছে?

জানা থাকলে for:

  • ৫ বার চালাতে হবে
  • ১ থেকে ১০০ পর্যন্ত যেতে হবে
  • একটা শব্দের প্রতিটি অক্ষর দেখতে হবে
  • একটা তালিকার প্রতিটি জিনিস নিয়ে কাজ করতে হবে

জানা না থাকলে while:

  • সঠিক ইনপুট না পাওয়া পর্যন্ত জিজ্ঞেস করতে হবে
  • ব্যবহারকারী quit না লেখা পর্যন্ত চলতে হবে
  • ফাইলে লাইন থাকা পর্যন্ত পড়তে হবে

সন্দেহ হলে for বেছে নিন। কারণ সোজা: for লুপ থেমে যাওয়ার নিশ্চয়তা দেয়, while দেয় না। যেখানে দুটোই খাটে, সেখানে যেটা কম ভুল হতে দেয় সেটাই ভালো পছন্দ।


একটা সম্পূর্ণ উদাহরণ

multiplication.py:

python
# Print a multiplication table, then a small summary
number = int(input("Which table? "))
upto = int(input("Up to?       "))

print()
print(f"--- Table of {number} ---")

total = 0
for i in range(1, upto + 1):
    result = number * i
    total = total + result
    print(f"{number} x {i:2} = {result:4}")

print()
print(f"Rows    : {upto}")
print(f"Sum     : {total}")
print(f"Average : {total / upto:.2f}")
text
Which table? 7
Up to?       5

--- Table of 7 ---
7 x  1 =    7
7 x  2 =   14
7 x  3 =   21
7 x  4 =   28
7 x  5 =   35

Rows    : 5
Sum     : 105
Average : 21.00

তিনটি জিনিস লক্ষ্য করুন। এক, range(1, upto + 1) — upto পর্যন্ত পেতে এক বেশি লিখতে হয়েছে। দুই, {i:2} আর {result:4} — f-string-এর ভেতরে সংখ্যাটা কত ঘর জায়গা নেবে তা বলে দেওয়া যায়, যাতে কলামগুলো সোজা থাকে। তিন, total লুপের বাইরে শুরু, ভেতরে জমছে — সেই একই অ্যাকিউমুলেটর।

আর একটা প্রশ্ন নিজেকে করুন: ব্যবহারকারী Up to?-এর জায়গায় 0 লিখলে কী হবে? range(1, 1) কোনো সংখ্যাই দেয় না, তাই লুপ একবারও চলে না — আর তারপর total / upto মানে শূন্য দিয়ে ভাগ। আগের মিশনের সেই শিক্ষাটাই আবার: লুপের পরে জমা মান ব্যবহার করার আগে যাচাই করে নিতে হয়।


কিছু ভাঙা অবস্থা ও তার সমাধান

শেষ সংখ্যাটা বাদ পড়ে যাচ্ছে range(1, 10) শেষ করে 9-এ। stop-এ এক বেশি দিন: range(1, 11)।

`TypeError: 'float' object cannot be interpreted as an integer range() শুধু পূর্ণসংখ্যা নেয়। range(2.5) বা range(1, n / 2) চলবে না — int() দিয়ে নিন, বা // দিয়ে ভাগ করুন।

`SyntaxError: expected ':' for লাইনের শেষে কোলন দেওয়া হয়নি।

`IndentationError: expected an indented block after 'for' statement লুপের ভেতরের লাইনটা ভেতরে ঠেলা হয়নি।

লুপ একবারও চলল না range ফাঁকা। range(5, 0) কিছুই দেয় না — বড় থেকে ছোটতে নামতে হলে তৃতীয় আর্গুমেন্টে -1 দিতে হয়: range(5, 0, -1)।

লুপের পরে যোগফল 0 আসছে total = 0 লাইনটা লুপের ভেতরে ঢুকে গেছে, তাই প্রতিবার শূন্য হয়ে যাচ্ছে। ওটা বাইরে থাকতে হবে।

লুপের ভেতরের ভেরিয়েবলটা বাইরে দরকার, কিন্তু NameError আসছে range ফাঁকা হওয়ায় লুপ একবারও চলেনি, তাই ভেরিয়েবলটা তৈরিই হয়নি। লুপের আগে একটা শুরুর মান দিয়ে রাখুন।