if/else ও loop
এই পাঠে যা শিখবেন
- if/elif/else — শর্তসাপেক্ষ logic
- for loop — sequence ও range-এ iterate
- while loop — শর্ত-ভিত্তিক loop
- break, continue, else clause — control transfer
- Nested loop ও indentation-এর গুরুত্ব
১ · if/elif/else — সিদ্ধান্ত নেওয়া
Programming-এ "যদি … তাহলে …" — সবচেয়ে মৌলিক control structure। Python-এ এটি if keyword দিয়ে।
১) if condition: — শর্ত সত্য হলে।
২) elif condition: — আগেরটা মিথ্যা, এটা সত্য হলে। (যত খুশি)
৩) else: — কোনোটা না মিললে। (ঐচ্ছিক)
# গ্রেড নির্ণয়
score = 78
if score >= 80:
grade = "A+"
elif score >= 70:
grade = "A"
elif score >= 60:
grade = "A-"
elif score >= 50:
grade = "B"
else:
grade = "F"
print(f"Score: {score}, Grade: {grade}")
{} নেই। ভুল indent → IndentationError।
২ · Truthy ও Falsy — Python-এর "সত্য" কী?
# Falsy values — if-এ False হিসেবে ধরা হয়
falsy_examples = [False, 0, 0.0, "", [], {}, None]
for item in falsy_examples:
if item:
print(f"{repr(item)} → truthy")
else:
print(f"{repr(item)} → falsy")
# Pythonic check
data = []
if not data: # খালি list = falsy
print("কোনো ডেটা নেই")
if data: — Pythonic style। if len(data) > 0: বলার দরকার নেই। খালি collection নিজেই falsy।
৩ · for loop — sequence-এ iterate
Python-এর for "C-এর for"-এর মতো নয় — এটি iteratorIteratorএকটি object যা একে একে item দিতে পারে। __next__ method আছে। For loop নিজেই iterator-এর উপর চলে। Memory efficient — পুরোটা একসাথে নয়।-ভিত্তিক — for-each।
# list-এ iterate
fruits = ["আম", "জাম", "কাঁঠাল"]
for fruit in fruits:
print(f"আমি {fruit} খাই")
# range — সংখ্যা সিরিজ
for i in range(5): # 0, 1, 2, 3, 4
print(i, end=" ")
print()
for i in range(2, 10, 2): # 2, 4, 6, 8 (start, stop, step)
print(i, end=" ")
print()
# enumerate — index ও value একসাথে
for idx, fruit in enumerate(fruits):
print(f"{idx}: {fruit}")
range(stop), range(start, stop), range(start, stop, step) — তিন রূপ। AI-তে epoch loop, batch index — সর্বত্র।
৪ · while loop — শর্ত-ভিত্তিক
# Loss-এর simulation — যতক্ষণ না threshold-এ পৌঁছে
loss = 1.0
epoch = 0
threshold = 0.01
while loss > threshold:
loss = loss * 0.7 # ধীরে কমে
epoch += 1
print(f"Epoch {epoch}: loss={loss:.4f}")
print(f"\nthreshold-এ পৌঁছাতে {epoch} epoch লাগল")
৫ · break ও continue
# break — loop থামাও
print("=== break demo ===")
for n in range(20):
if n == 5:
break # খুঁজে পেয়েছি, আর দরকার নেই
print(n, end=" ")
print()
# continue — পরের iteration-এ যাও
print("=== continue demo ===")
for n in range(10):
if n % 2 == 0:
continue # জোড় skip
print(n, end=" ") # 1 3 5 7 9
print()
৬ · Nested loop
# গুণের নামতা — 2x2
for i in range(1, 4):
for j in range(1, 4):
print(f"{i}×{j}={i*j:2d}", end=" ")
print() # প্রতি row-এর শেষে newline
৭ · AI-তে loop-এর প্রয়োগ
# Mini training loop — pseudo
n_epochs = 5
batches = ["b1", "b2", "b3"]
for epoch in range(1, n_epochs + 1):
epoch_loss = 0
for batch in batches:
# forward, backward, update — pseudo
batch_loss = 1.0 / (epoch + 1) # demo decay
epoch_loss += batch_loss
avg = epoch_loss / len(batches)
print(f"Epoch {epoch}: avg_loss={avg:.4f}")
# early stopping
if avg < 0.2:
print("যথেষ্ট ভাল — training থামাও")
break
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
Python-এ {} না — indentation দিয়ে block। কেন এই radical সিদ্ধান্ত? এর সুবিধা ও ঝুঁকি কী? AI কোডের পঠনযোগ্যতার সাথে এর সম্পর্ক?
Indentation-as-syntax — Python-এর সবচেয়ে polarizing design choice। Guido van Rossum ১৯৯১-এ এই সিদ্ধান্ত নেন — programming history-তে যা বিরল।
Guido-র যুক্তি:
- "Code is read 10× more than written" — পঠনযোগ্যতা প্রথম priority।
- C/Java-এ — programmer এমনিতেও indent করে। তাহলে compiler কেন কেয়ার করে না?
- Indent ও
{}mismatch — confusing bug source। - "There should be one obvious way to do it" — Zen of Python।
সুবিধা:
- Visual ও syntactic structure সবসময় match।
- কোড dense নয় — air ও spacing।
- Diff ছোট — bracket লাইন থাকে না।
- Beginner-friendly — কম symbol।
ঝুঁকি ও সমস্যা:
- Tab/space mixing: Python ৩-এ illegal, কিন্তু legacy code-এ চলে।
- Copy-paste subtle bug: editor-এ indent বদলে গেলে behavior বদলায়।
- Email/chat-এ code paste: indentation চলে যায়।
- Multi-line lambda অসম্ভব — single line-এ আটকে।
- Auto-formatting tool কঠিন: "correct" indent কী — context-নির্ভর।
Tooling-এর সমাধান:
- Black: opinionated formatter — সবার কোড একই দেখায়।
- ruff: ১০০× দ্রুত linter+formatter (Rust-এ লেখা)।
- EditorConfig: team-wide editor settings।
- pre-commit hooks: push-এর আগে auto-format।
AI কোডে এর তাৎপর্য:
- Notebook cell-এ paste করে "running" — indent ভুল কামড় দেয়।
- Deep nested model code — visual structure কোড পড়া সহজ করে।
- Stack Overflow থেকে copy — সবসময় re-indent।
- Jupyter-এ shift+tab indent helpful।
অন্য language-এ এই philosophy:
- Haskell, F# — optional indent-based syntax।
- YAML — pure indent-based (controversial)।
- Go — tab-only enforced।
- Rust — formatter rustfmt enforced।
মূল উপলব্ধি: Indent = visual contract। ভাল IDE + Black = সমস্যা শেষ। Beginners-এর জন্য awkward, পেশাদারদের জন্য liberation। Python = "executable pseudocode"-এর spirit এই indent-এ।
প্র ০২ "Loop ব্যবহার এড়িয়ে চল — vectorize কর" — AI/ML-এ কেন এই pure mantra? Python-এ for loop এত ধীর কেন? GPU-এর সাথে এর সম্পর্ক কী?
Vectorization — AI performance-এর সবচেয়ে গুরুত্বপূর্ণ একক ধারণা। এটা না বুঝলে — production AI কোড impossible।
Python for loop কেন ধীর?
- প্রতি iteration-এ Python interpreter overhead — bytecode dispatch, type checking।
- প্রতি element-এ object allocation/dereference।
- GIL (Global Interpreter Lock) — multi-thread parallelism নেই।
- CPython implementation — JIT নেই (PyPy-তে আছে)।
Vectorization কী?
- Operation একটি element-এ নয়, পুরো array-এ একসাথে।
- NumPy
a + b— Python loop নয়, C-তে SIMD instruction। - GPU-তে — হাজার core parallel।
Concrete benchmark:
# ১ লক্ষ float-এর square
# Python loop:
result = []
for x in data:
result.append(x * x)
# 50 ms
# NumPy vectorized:
result = data ** 2
# 0.5 ms — ১০০× দ্রুত
# GPU (PyTorch):
result = data.cuda() ** 2
# 0.05 ms — ১০০০× দ্রুত
SIMD-এর জাদু:
- "Single Instruction, Multiple Data" — একটি CPU instruction ৪/৮/১৬টি float একসাথে।
- AVX-512 — ১৬ float একসাথে (Intel Skylake+)।
- GPU SIMT — হাজার thread।
কখন loop ঠিক আছে?
- Loop-এর body-তে I/O (file, network) — bottleneck Python নয়।
- Sequential dependency — RNN unrolling।
- Small data — overhead worth it নয়।
- Outer training loop — epoch ৫০, vectorize-এর কিছু নেই।
Vectorization-এর প্যাটার্ন:
- Replace explicit loop:
[x*2 for x in lst]→arr * 2। - Broadcasting: shape mismatch auto-resolve।
- Boolean masking:
arr[arr > 0]— filter without loop। - Reduction:
arr.sum(),arr.mean()।
"Numpy thinking" — paradigm shift:
- প্রশ্ন: "প্রতিটি element-এর জন্য কী করব?" — wrong।
- প্রশ্ন: "পুরো array-কে কোন function-এ পাঠাব?" — right।
- Brain-এর reflex বদল — সময় লাগে।
মূল উপলব্ধি: Loop = কম্পিউটারের natural language। Vectorize = mathematician-এর natural language। AI = math-heavy → vectorize default। L09–L12-এ NumPy-তে এই thinking তৈরি হবে।
প্র ০৩
Python-এ for loop-এর সাথে else clause আছে — অদ্ভুত feature। কখন কাজে লাগে? Real AI কোডে এর প্রয়োগ কোথায়?
Python-এর for-else — সবচেয়ে confusing feature, কিন্তু চমৎকার pattern।
Behavior: for/while loop normally complete (break ছাড়া) হলে else block চলে।
for x in data:
if x == target:
print("পাওয়া গেছে")
break
else:
print("নেই") # break না হলে এই block
Why "else"? — name বিভ্রান্তিকর:
- Knuth-এর মতে এটি "nobreak" বলা উচিত ছিল।
- "else" অর্থ — "if you didn't break"।
- Guido নিজে এটি পছন্দ নাম স্বীকার করেছেন।
সাধারণ pattern — search:
# খারাপ — flag variable
found = False
for x in data:
if x == target:
found = True
break
if not found:
handle_missing()
# ভাল — for/else
for x in data:
if x == target:
process(x)
break
else:
handle_missing()
AI কোডে কাজের examples:
- Convergence check:
for epoch in range(max_epochs): train_one_epoch() if loss < threshold: print(f"Converged at epoch {epoch}") break else: print("Did not converge") # max_epochs শেষ - Hyperparameter search:
for lr in lr_grid: if try_train(lr) > 0.95: best_lr = lr break else: raise ValueError("কোনো learning rate কাজ করেনি") - Validation:
for sample in batch: if not validate(sample): raise ValueError(f"Invalid: {sample}") break else: proceed_to_train()
সমালোচনা:
- অপরিচিতদের জন্য বিভ্রান্তিকর।
- Code review-এ comment ছাড়া পড়া কঠিন।
- অনেক senior dev এড়িয়ে চলেন।
Alternatives:
- Function + early return:
def find(target, data): for x in data: if x == target: return x return None - সাধারণত — function-এ wrap করা cleaner।
মূল উপলব্ধি: for-else exotic কিন্তু powerful। জানা থাকলে — "did the loop finish without break?" pattern এক structure-এ। আজকের preference — function-এ encapsulate, কিন্তু legacy কোড পড়তে এই knowledge দরকার।
প্র ০৪
Conditional logic বেশি হলে — if/elif chain কুৎসিত হয়। Python 3.10-এ match/case এসেছে। Strategy pattern, dict dispatch — alternatives কী কী? কখন কোনটা?
Branching logic বাড়লে — কোড maintainability ভেঙে পড়ে। Modern Python-এ এর কয়েকটি সুন্দর pattern আছে।
সমস্যার রূপ:
# ১০টি case — কুৎসিত
def get_optimizer(name):
if name == "sgd":
return SGD(...)
elif name == "adam":
return Adam(...)
elif name == "rmsprop":
return RMSprop(...)
# ... আরও
সমাধান ১: Dict dispatch (Pythonic):
OPTIMIZERS = {
"sgd": SGD,
"adam": Adam,
"rmsprop": RMSprop,
}
def get_optimizer(name, **kwargs):
cls = OPTIMIZERS.get(name)
if cls is None:
raise ValueError(f"Unknown: {name}")
return cls(**kwargs)
- O(1) lookup। Extensible — নতুন entry শুধু dict-এ।
- Test data-driven।
- Plugin architecture-এর ভিত্তি।
সমাধান ২: match/case (Python 3.10+, ২০২১):
def parse_command(cmd):
match cmd:
case ["train", model, *args]:
train(model, args)
case ["predict", model, input]:
predict(model, input)
case ["save", path]:
save(path)
case _:
raise ValueError("Unknown command")
- Structural pattern matching — Rust/Haskell-এর মতো।
- Destructuring + condition একসাথে।
- Complex data structure-এর জন্য আদর্শ।
সমাধান ৩: Strategy pattern (OO):
class Strategy:
def execute(self, x): ...
class FastStrategy(Strategy):
def execute(self, x): return x * 2
class SafeStrategy(Strategy):
def execute(self, x): return x
- Strategy ভিন্ন ভিন্ন behavior একই interface-এ।
- Heavy কাজ, configurable।
সমাধান ৪: Polymorphism (duck typing):
- Python "if isinstance(x, ...)" এড়াও।
- Object-এর method call — type ignore।
AI-তে concrete:
- Model registry: Hugging Face Transformers — model name string → class।
- Loss function: "mse"/"crossentropy"/"focal" → callable।
- Activation: "relu"/"gelu"/"silu" → torch function।
- Data augmentation: recipe → list of operations।
কখন কোনটা — guideline:
- ২-৩টি case → simple if/elif।
- ৪-১০টি case → dict dispatch।
- Pattern matching, destructuring → match/case।
- Complex behavior → Strategy class।
- Deep type hierarchy → polymorphism।
"Replace conditional with polymorphism" — Martin Fowler:
- Refactoring book-এর famous pattern।
- OOP দিয়ে if/else explosion দূর।
মূল উপলব্ধি: If/elif chain — code smell। ১০-এর বেশি — refactor। AI ML codebase-এ — registry pattern + dict dispatch + match/case = clean architecture। L05-এ function ও lambda — এই idiom-এর বিল্ডিং ব্লক।
অনুশীলন
-
FizzBuzz: 1 থেকে 15 print করুন। কিন্তু — ৩-এর গুণিতকে "Fizz", ৫-এর গুণিতকে "Buzz", দু'টোর গুণিতকে "FizzBuzz"।
for n in range(1, 16): if n % 15 == 0: print("FizzBuzz") elif n % 3 == 0: print("Fizz") elif n % 5 == 0: print("Buzz") else: print(n)মনে রাখুন — ১৫-এর check আগে। নাহলে "Fizz" বা "Buzz" দিয়ে শেষ হয়ে যাবে।
-
Factorial: ৬-এর factorial (১×২×৩×৪×৫×৬) loop দিয়ে হিসাব করুন।
result = 1 for i in range(1, 7): result *= i print(f"6! = {result}") # 720 -
সর্বোচ্চ খুঁজুন: একটি list-এ সবচেয়ে বড় সংখ্যা loop দিয়ে বের করুন (built-in max ছাড়া)।
nums = [12, 45, 7, 89, 23, 56, 34] biggest = nums[0] for n in nums[1:]: if n > biggest: biggest = n print(f"সর্বোচ্চ: {biggest}") # 89
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ০৫ · Function ও Lambda পরবর্তী পাঠ Code-এর reusable block — ৫০টি লাইন → ১টি function call।
- পাঠ ০৩ · List, Tuple ও Dictionary আগের পাঠ
- পাঠ ০৬ · List comprehension ও iterator সম্পর্কিত Loop-এর Pythonic alternative — এক লাইনে।
- সব AI Courses দেখুন ABCL TECH