সরাসরি পর্বে যান
পর্ব ১১ · ৫৫-এর মধ্যে · মডিউল ২

সিদ্ধান্ত — if/elif/else আর match-case

Decisions in Python — if / elif / else and Structural Pattern Matching

Taught in Bangla, this lesson teaches decisions in Python: if, elif and else with indentation-based blocks, nested conditions versus guard clauses, truthiness and is None checks, and structural pattern matching with match-case, including sequence and mapping patterns and the capture-pattern trap.

এই পর্বে যা শিখবেন

  • if, elif, else দিয়ে প্রোগ্রামকে পথ বাছাই করানো, আর block ও indentation-এর নিয়ম
  • elif-এর ক্রম কেন ফল বদলে দেয় — পরীক্ষার গ্রেড বের করার উদাহরণে
  • Nested if, সমতল elif আর guard clause — কখন কোনটি পড়তে সহজ
  • শর্তে truthiness, is None, এক লাইনের conditional expression আর pass
  • match-case: literal, |, _, capture, guard, sequence ও mapping pattern — আর খালি নামের ফাঁদ

১ · প্রোগ্রাম যখন পথ বেছে নেয়

এ পর্যন্ত আপনার সব প্রোগ্রাম চলেছে একটি সোজা রাস্তায় — প্রথম লাইন, তারপর দ্বিতীয়, তারপর তৃতীয়। প্রতিবার চালালে প্রতিটি লাইন চলে। কিন্তু বাস্তবের কাজ এমন নয়। মেট্রোরেলের গেটে কার্ড ছোঁয়ালে গেট খোলে যদি কার্ডে টাকা থাকে; না থাকলে লাল বাতি জ্বলে। পরীক্ষার ফলাফলের সফটওয়্যার নম্বর দেখে ঠিক করে কে A+ পাবে, কে A. মোবাইলে ভুল PIN দিলে অ্যাপ বলে “আবার চেষ্টা করুন”।

প্রতিটি ক্ষেত্রে প্রোগ্রাম একটি প্রশ্ন করে, আর উত্তর অনুযায়ী একটি পথ বেছে নেয়। প্রশ্নটিকে বলে শর্ত (condition) — এমন একটি হিসাব, যার ফল হয় True নয়তো False. এ ধরনের মানের type হলো bool. যে কোড শর্ত দেখে পথ বাছাই করে, তাকে বলে সিদ্ধান্ত বা if statement.

মেট্রো গেটের সিদ্ধান্ত

একটি শর্ত, দুটি পথ, তারপর আবার একসাথে

  1. কার্ড ছোঁয়ানোbalance = 35আগের লাইন
  2. শর্তbalance >= fareTrue না False?
  3. True হলেopen_gate()if-এর block
  4. False হলেshow_red()else-এর block
ছবি ১১.১ — দুটি পথের যেকোনো একটিই চলে, কখনো দুটো একসাথে নয়। তারপর প্রোগ্রাম আবার একই রাস্তায় এগোয়।

শর্ত লেখার উপকরণ আপনি আগেই শিখেছেন, তাই এখানে শুধু এক অনুচ্ছেদে মনে করিয়ে দিই। পর্ব ০৮-এ দেখেছেন তুলনার operator (==, !=, <, >, <=, >=), যার ফল True বা False; যুক্তির operator and, or, not, যারা দরকার না হলে দ্বিতীয় অংশ পরীক্ষাই করে না (short-circuit); আর is বনাম ==-এর পার্থক্য। Python-এ 18 <= age < 60-এর মতো তুলনা শিকলের মতো জোড়াও লাগানো যায়। পর্ব ০৬ ও ০৮-এ আরেকটি ধারণা এসেছে — truthiness: 0, ফাঁকা string "", ফাঁকা list [], None — এগুলো শর্তের জায়গায় বসলে “মিথ্যা” ধরা হয়, বাকি প্রায় সবকিছু “সত্য”। এই পর্বে এসব উপকরণ দিয়ে আসল সিদ্ধান্ত বানাব।

ঢাকার একটি মোড়ে দাঁড়ানো ট্রাফিক পুলিশের কথা ভাবুন। তিনি একটি প্রশ্ন করেন — “এই রাস্তায় জ্যাম আছে?” — আর উত্তর অনুযায়ী হাত দেখিয়ে গাড়িকে ডানে বা সোজা পাঠান। গাড়িটি একসাথে দুই রাস্তায় যেতে পারে না, আবার মোড় পেরোনোর পর দুই রাস্তা হয়তো সামনে গিয়ে মিলেও যায়। if হলো সেই পুলিশ; শর্ত হলো তাঁর প্রশ্ন; আর block হলো প্রতিটি রাস্তা।

২ · if, else আর block — indentation-ই কোডের কাঠামো

সবচেয়ে সরল সিদ্ধান্তে একটি শর্ত আর একটি পথ থাকে। শর্ত মিথ্যা হলে ভেতরের কোড বাদ পড়ে যায়, প্রোগ্রাম সোজা এগোয়:

balance = 35
fare = 40

if balance >= fare:
    print("গেট খুলছে")
    balance = balance - fare
else:
    print("টাকা কম — রিচার্জ করুন")

print("বাকি:", balance)

লাইনগুলো খেয়াল করে পড়ুন। if-এর পর শর্ত, তারপর একটি কোলন :. কোলনের মানে “এরপর একটি block আসছে”। পরের লাইনগুলো ৪ space ডানে সরানো — এগুলোই শর্ত সত্য হলে চলবে। else: মানে “না হলে”; তার block চলবে শর্ত মিথ্যা হলে। শেষের print("বাকি:", balance) আবার বাম দেয়ালে ফিরে এসেছে, তাই এটি কোনো block-এর অংশ নয় — সবসময় চলবে। এখানে 35 < 40, তাই আউটপুট “টাকা কম — রিচার্জ করুন” আর “বাকি: 35”.

মূল ধারণা

Python-এ block (একসাথে চলা লাইনের দল) চিহ্নিত হয় শুধু indentation দিয়ে। একই পরিমাণ সরানো পরপর লাইনগুলো একটি block. বাম দিকে ফিরে এলেই block শেষ। C, Java বা JavaScript-এ এই কাজ করে { }, আর indentation সেখানে শুধু মানুষের চোখের আরাম — compiler সেটা দেখেই না। Python-এ চোখ যা দেখে আর মেশিন যা বোঝে, দুটো একই জিনিস। কোডের আকারই কোডের অর্থ।

Indentation-এর নিয়ম

  • ৪ space ব্যবহার করুন। ভাষা যেকোনো সমান পরিমাণ মেনে নেয়, কিন্তু Python-এর লেখার নির্দেশিকা PEP 8 বলে প্রতি স্তরে ৪ space. VS Code-এ Tab চাপলে Python ফাইলে নিজে থেকেই ৪ space বসে।
  • একটি block-এর সব লাইন সমান সরানো থাকবে। একটি লাইন ৪ আর পরেরটি ৩ space হলে Python বিভ্রান্ত হয়ে error দেয়।
  • Tab আর space মেশাবেন না। Python 3 এমন মিশ্রণ অস্পষ্ট হলে TabError দেয়। অন্য কোথাও থেকে কোড কপি করলে এটি প্রায়ই ঘটে।
  • Block ফাঁকা রাখা যায় না। কোলনের পর অন্তত একটি সরানো লাইন লাগবেই। এখনো কিছু লেখার না থাকলে pass লিখুন (অংশ ৫)।

ভুল হলে Python চালানোর আগেই থামিয়ে দেয়। পর্ব ০৪-এ দেখা IndentationError এর সবচেয়ে সাধারণ রূপ:

  File "metro.py", line 5
    print("গেট খুলছে")
    ^^^^^
IndentationError: expected an indented block after 'if' statement on line 4

মেসেজটি সোজা কথা বলছে: লাইন ৪-এর if-এর পর একটি সরানো block আশা করা হয়েছিল, কিন্তু লাইন ৫ সরানো নেই। পর্ব ০৫-এ দেখেছেন, indentation tokenizer-এর ধাপেই INDENT/DEDENT token হয়ে যায় — তাই এই error ফাইলের একটি লাইন চলার আগেই আসে।

সবচেয়ে বিপজ্জনক indentation-ভুল কিন্তু error দেয় না। ওপরের উদাহরণে balance = balance - fare লাইনটি ভুল করে বাম দেয়ালে চলে গেলে সেটি আর if-এর অংশ থাকে না — গেট না খুললেও টাকা কেটে যাবে! Python কোনো আপত্তি করবে না, কারণ সেটাও বৈধ কোড। তাই কোড পড়ার সময় প্রতিটি লাইনের বাম কিনারা দেখুন: “এই লাইনটি কার ভেতরে?”

C/C++ জানলে

C-তে শর্ত বন্ধনীর ভেতরে লিখতে হয় — if (x > 0) { ... } — আর Python-এ বন্ধনী লাগে না, কোলন আর indentation লাগে। C-র else if Python-এ এক শব্দে elif. C-র switch শুধু পূর্ণসংখ্যার ধ্রুবক তুলনা করে আর break না দিলে পরের case-এ গড়িয়ে পড়ে; Python-এর match কখনো গড়িয়ে পড়ে না, আর তুলনা করে ডেটার পুরো আকার। C-র দিকটি বিস্তারিত দেখতে পড়ুন C কোর্সের সিদ্ধান্ত — if আর switch.

Indentation দিয়ে block বোঝানোর ধারণা Guido van Rossum পেয়েছিলেন ABC নামের একটি শিক্ষণ-ভাষা থেকে, যা ১৯৮০-র দশকে নেদারল্যান্ডসের CWI-তে তৈরি হয় এবং যার দলে Guido নিজেও কাজ করেছিলেন। শর্তের পর কোলন : বসানোর অভ্যাসও ABC থেকে এসেছে — সেখানে ব্যবহারকারী-পরীক্ষায় দেখা গিয়েছিল, কোলন থাকলে নতুনরা block-এর শুরু সহজে চেনে।

৩ · elif — অনেক পথ, কিন্তু প্রথম সত্যটিই জেতে

দুটির বেশি পথ দরকার হলে আসে elif (“else if”-এর সংক্ষেপ)। একটি if, তারপর যত খুশি elif, শেষে ইচ্ছা হলে একটি else. সবচেয়ে পরিচিত উদাহরণ — নম্বর থেকে গ্রেড। নিচের টেবিলটি বাংলাদেশের SSC/HSC-ধাঁচের গ্রেডিং স্কেলের একটি উদাহরণ; আপনার প্রতিষ্ঠানের স্কেল ভিন্ন হলে সংখ্যাগুলো বদলে নিলেই চলবে।

নম্বরগ্রেডপয়েন্ট
৮০–১০০A+৫.০০
৭০–৭৯A৪.০০
৬০–৬৯A-৩.৫০
৫০–৫৯B৩.০০
৪০–৪৯C২.০০
৩৩–৩৯D১.০০
০–৩২F০.০০

এই স্কেল কোডে লেখার সময় একটি নিয়ম মাথায় রাখুন: Python if/elif-এর শর্তগুলো ওপর থেকে নিচে, একটা একটা করে পরীক্ষা করে। প্রথম যে শর্তটি সত্য হয়, শুধু তার block চলে — তারপর পুরো সারি থেকে বেরিয়ে যায়। নিচের শর্তগুলো আর দেখাই হয় না। এই নিয়মের সুবিধা হলো, elif marks >= 70 লেখার সময় “এবং 80-এর কম” লিখতে হয় না — 80 বা বেশি হলে তো আগের ধাপেই বেরিয়ে যেত। আর বিপদ হলো, ক্রম উল্টে গেলে কী হয়, নিচে দেখুন। “পরে” চাপুন:

1if marks >= 80:2    grade = "A+"3elif marks >= 70:4    grade = "A"5elif marks >= 60:6    grade = "A-"7else:8    grade = "F"9print(grade)
অবস্থা (সঠিক ক্রম)
marks
শর্ত
grade
1if marks >= 60:2    grade = "A-"3elif marks >= 70:4    grade = "A"5elif marks >= 80:6    grade = "A+"7else:8    grade = "F"9print(grade)
অবস্থা (উল্টো ক্রম)
marks
শর্ত
grade
  1. প্রথম শর্ত। Python লাইন ১ পরীক্ষা করে: 73 >= 80? না, False. লাইন ২-এর block বাদ, পরের elif-এ যায়।
  2. দ্বিতীয় শর্ত সত্য। লাইন ৩: 73 >= 70? হ্যাঁ, True. এটিই প্রথম সত্য শর্ত, তাই এর block-এ ঢোকে। খেয়াল করুন, “80-এর কম কি না” আলাদা করে দেখতে হয়নি।
  3. Block চলল। লাইন ৪: grade হলো "A".
  4. বাকি সব বাদ। লাইন ৫ থেকে ৮ — একটিও পরীক্ষা হয় না, যদিও 73 >= 60-ও সত্য। Python সোজা লাইন ৯-এ চলে যায় আর A ছাপে। এবার দেখুন একই শর্তগুলো উল্টো ক্রমে লিখলে কী হয়।
  5. উল্টো ক্রম — প্রথম শর্তেই সত্য। এবার সবচেয়ে ঢিলা শর্তটি ওপরে: 73 >= 60? True. প্রথম সত্য শর্ত পেয়ে গেছে!
  6. ভুল block চলল। grade হলো "A-", আর বাকি সারি বাদ। কোনো error নেই, কোনো সতর্কবার্তা নেই।
  7. নীরব bug. A- ছাপা হলো। আরও খারাপ: 95 দিলেও A- আসবে, কারণ 60-এর বেশি যেকোনো নম্বর প্রথম শর্তেই আটকে যায়। “A” আর “A+”-এর শাখা কখনোই চলবে না — এগুলো dead code. নিয়ম: সীমা দিয়ে ভাগ করলে সবচেয়ে কড়া শর্ত সবার ওপরে।

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

marks = int(input("নম্বর লিখুন: "))

if marks < 0 or marks > 100:
    grade = "ভুল নম্বর"
elif marks >= 80:
    grade = "A+"
elif marks >= 70:
    grade = "A"
elif marks >= 60:
    grade = "A-"
elif marks >= 50:
    grade = "B"
elif marks >= 40:
    grade = "C"
elif marks >= 33:
    grade = "D"
else:
    grade = "F"

result = "পাস" if grade in ("A+", "A", "A-", "B", "C", "D") else "পাস নয়"
print(f"নম্বর {marks} → গ্রেড {grade} ({result})")

এখানে ইনপুট হিসেবে 73 দেওয়া হয়েছে, তাই আউটপুট নম্বর লিখুন: নম্বর 73 → গ্রেড A (পাস) — প্রথম অংশটি input()-এর প্রশ্ন, যা নতুন লাইন ছাড়াই ছাপা হয় (পর্ব ১০)। সবার ওপরের শর্তটি একটি পাহারা: −৫ বা ১৫০-এর মতো অসম্ভব নম্বর আগেই ধরে ফেলে, নইলে ১৫০ পেত A+. শেষের else সব বাকি ক্ষেত্র (০ থেকে ৩২) ধরে — তাই কোনো নম্বরেই grade খালি থাকে না। নিজের কম্পিউটারে 80, 79, 33, 32, 101 দিয়ে চালিয়ে সীমার মানগুলো পরীক্ষা করুন — bug সাধারণত সীমাতেই লুকিয়ে থাকে।

if-এর পর elif আর else দুটোই ঐচ্ছিক। কিন্তু elif সবসময় if-এর পরে, আর else থাকলে সবার শেষে — একটিই। আরেকটি পার্থক্য মনে রাখুন: পরপর তিনটি আলাদা if লিখলে তিনটিই পরীক্ষা হয়, একাধিক block চলতে পারে; একটি if/elif সারিতে সর্বোচ্চ একটি block চলে। গ্রেডের কোডে elif-এর বদলে সব if লিখলে 85 নম্বরে grade প্রথমে A+, তারপর A, তারপর A-… শেষ পর্যন্ত যা থাকবে তাই — আরেকটি নীরব bug.

৪ · Nested if, সমতল elif আর guard clause

একটি if-এর block-এর ভেতরে আরেকটি if রাখা যায় — একে বলে nested if. কখনো এটি স্বাভাবিক: “লগইন করা থাকলে — তারপর অ্যাডমিন হলে — মুছতে দাও”। কিন্তু স্তর বাড়তে থাকলে কোড ডান দিকে সরতে সরতে একটি পিরামিডের মতো দেখায়, আর কোন else কোন if-এর, তা খুঁজতে চোখ ঘামে। প্রোগ্রামাররা একে মজা করে বলেন “arrow code” — কোডের আকার তীরের ফলার মতো।

উদাহরণ: একটি বাস কোম্পানির ভাড়া হিসাব। নিয়মগুলো উদাহরণ মাত্র — দূরত্ব শূন্য বা ঋণাত্মক হলে হিসাব বাতিল (None); ৩ বছরের কম বয়সী শিশু আর ৬৫ বা বেশি বয়সী প্রবীণের ভাড়া নেই; ছাত্রছাত্রী কিলোমিটারপ্রতি ১ টাকা, বাকিরা ২ টাকা। ফাংশন (def) পর্ব ১৩-এর বিষয়; এখানে শুধু জানুন, return উত্তরটি ফেরত দিয়ে সঙ্গে সঙ্গে ফাংশন থেকে বেরিয়ে যায়। এই “সঙ্গে সঙ্গে বেরিয়ে যাওয়া”ই guard clause-এর চাবি। কোডটি ধাপে ধাপে বদলাতে দেখুন:

fare.py — শুরুর রূপ৪ স্তর গভীর
def ticket_fare(age, is_student, km):
    if km > 0:
        if age >= 3:
            if age < 65:
                if is_student:
                    return km * 1
                else:
                    return km * 2
            else:
                return 0
        else:
            return 0
    else:
        return None
ধাপ ১ভুল ইনপুট সবার আগে বিদায়
def ticket_fare(age, is_student, km):
    if km <= 0:
        return None
    if age >= 3:
        if age < 65:
            if is_student:
                return km * 1
            else:
                return km * 2
        else:
            return 0
    else:
        return 0
ধাপ ২বিশেষ ক্ষেত্রগুলোও আগে
def ticket_fare(age, is_student, km):
    if km <= 0:
        return None
    if age < 3 or age >= 65:
        return 0
    if is_student:
        return km * 1
    else:
        return km * 2
শেষ রূপমূল কাজ নিচে, সোজা পথে
def ticket_fare(age, is_student, km):
    if km <= 0:                 # guard: অবৈধ
        return None
    if age < 3 or age >= 65:    # guard: ফ্রি
        return 0
    rate = 1 if is_student else 2
    return km * rate
  1. পিরামিড। আসল কাজ (ভাড়া হিসাব) লুকিয়ে আছে চতুর্থ স্তরে। নিচের তিনটি else কোন if-এর, তা মেলাতে আঙুল দিয়ে কলাম ধরে ওপরে উঠতে হয়। “দূরত্ব শূন্য হলে কী হয়?” — উত্তর আছে একেবারে শেষ লাইনে, শর্ত থেকে বারো লাইন দূরে।
  2. শর্ত উল্টে আগে বিদায়। if km > 0: ... else: return None-কে উল্টে লিখুন: if km <= 0: return None. এই লাইনটি একটি guard clause — দরজার পাহারাদার, যে অবৈধ ক্ষেত্রকে ঢুকতেই দেয় না। return ফাংশন থেকে বের করে দেয় বলে পরের কোডে আর else লাগে না, পুরো বাকি কোড এক স্তর বামে সরে এল।
  3. বিশেষ ক্ষেত্র একসাথে। শিশু আর প্রবীণ — দুজনেরই ভাড়া শূন্য। দুটি nested শাখা জুড়ে একটি guard: if age < 3 or age >= 65: return 0. এভাবে আগে বিদায় নেওয়াকে বলে early return.
  4. সোজা পথ। সব বিশেষ ক্ষেত্র ওপরে বিদায় নিয়েছে, তাই নিচে থাকল শুধু সাধারণ ক্ষেত্র — কোনো স্তর ছাড়াই। ফাংশনটি এখন ওপর থেকে নিচে একটি তালিকার মতো পড়া যায়: “অবৈধ? বাতিল। ফ্রি? শূন্য। বাকিদের — রেট গুণ দূরত্ব।” আচরণ একদম একই, শুধু পড়া সহজ।

তিনটি ধরনের তুলনা মনে রাখুন। Nested if ঠিক আছে যখন প্রশ্নগুলো সত্যিই একটির ওপর আরেকটি নির্ভর করে, আর গভীরতা দুই স্তরের বেশি নয়। সমতল elif সেরা যখন একটি মানকে কয়েকটি পরস্পর-বিচ্ছিন্ন ভাগে ফেলতে হয় (গ্রেড, বিদ্যুৎ বিলের স্তর)। আর guard clause সেরা যখন কয়েকটি ব্যতিক্রম বাদ দিয়ে একটি মূল কাজ করতে হয় — ইনপুট যাচাই, অনুমতি পরীক্ষা, ফাঁকা ডেটা।

def electricity_bill(units):
    if units <= 75:
        return units * 5
    elif units <= 200:
        return 75 * 5 + (units - 75) * 7
    elif units <= 300:
        return 75 * 5 + 125 * 7 + (units - 200) * 8
    else:
        return 75 * 5 + 125 * 7 + 100 * 8 + (units - 300) * 10

স্তরভিত্তিক (slab) বিদ্যুৎ বিল: প্রথম ৭৫ ইউনিট ৫ টাকা, পরের ১২৫ ইউনিট ৭ টাকা, পরের ১০০ ইউনিট ৮ টাকা, তার বেশি ১০ টাকা করে। এই হারগুলো শুধু বোঝানোর জন্য — আসল হার সরকার সময়ে সময়ে বদলায়। প্রতিটি স্তর আগের সব স্তরের পুরো দাম যোগ করে, তারপর নিজের অংশ। এখানে elif-এর সারি স্বাভাবিক, কারণ একটি সংখ্যাকে সীমা দিয়ে ভাগ করা হচ্ছে।

def send_money(balance, amount, pin_ok):
    if not pin_ok:
        return "PIN ভুল"
    if amount <= 0:
        return "টাকার পরিমাণ সঠিক নয়"
    if amount > balance:
        return "ব্যালান্স যথেষ্ট নয়"
    return f"{amount} টাকা পাঠানো হলো"

মোবাইল ব্যাংকিং-ধাঁচের একটি যাচাই। প্রতিটি ব্যর্থতার কারণ নিজের লাইনে, নিজের বার্তায়। নতুন নিয়ম (যেমন দৈনিক সীমা) এলে আরেকটি guard যোগ করলেই হয় — বাকি কোডে হাত দিতে হয় না। মূল কাজটি — টাকা পাঠানো — সবার শেষে, কোনো indentation ছাড়া।

“Guard clause” নামটি জনপ্রিয় হয় Kent Beck-এর লেখা আর Martin Fowler-এর ১৯৯৯ সালের বই Refactoring-এর মাধ্যমে, যেখানে একটি কৌশলের নামই “Replace Nested Conditional with Guard Clauses”. Edsger Dijkstra-ও ১৯৭৫ সালে “guarded command” নামে শর্ত দিয়ে পাহারা দেওয়া নির্দেশের ধারণা দিয়েছিলেন — তবে সেটি একটু ভিন্ন, তাত্ত্বিক ধারণা।

৫ · শর্তের ছোট কিন্তু জরুরি কৌশল — truthiness, is None, এক লাইনের সিদ্ধান্ত আর pass

Truthiness: if items: বনাম if len(items) > 0:

শর্তের জায়গায় শুধু True/False নয়, যেকোনো মান বসানো যায় — Python তখন মানটির truthiness দেখে। তাই “list-এ কিছু আছে কি না” জানতে Pythonic লেখা হলো:

cart = []
name = input("নাম: ").strip()

if cart:                      # len(cart) > 0 লেখার দরকার নেই
    print("চেকআউট করুন")
else:
    print("ঝুড়ি খালি")

if not name:                  # name == "" এর সমান
    name = "অতিথি"

if cart: পড়তে প্রায় বাংলা বাক্যের মতো — “ঝুড়িতে কিছু থাকলে”। PEP 8-ও ফাঁকা ক্রম পরীক্ষায় এভাবেই লিখতে বলে। কিন্তু একটি সতর্কতা: truthiness একসাথে অনেক কিছুকে “মিথ্যা” ধরে। if score: লিখলে score-এর মান 0 হলেও শর্ত মিথ্যা হবে — অথচ শূন্য নম্বরও একটি বৈধ নম্বর!

if x is None — “কোনো মান নেই” আর “মান শূন্য” আলাদা

None হলো Python-এর “কিছুই নেই” — যেমন ওপরের ভাড়া-ফাংশন অবৈধ দূরত্বে None ফেরত দেয়। এখন ফল পরীক্ষা করুন:

fare = ticket_fare(70, False, 12)   # প্রবীণ: ভাড়া 0

if not fare:                # ভুল! 0 আর None দুটোই এখানে ঢোকে
    print("হিসাব বাতিল")

if fare is None:            # ঠিক: শুধু None
    print("হিসাব বাতিল")
elif fare == 0:
    print("বিনা ভাড়ায় যাত্রা")

প্রথম শর্তটি প্রবীণ যাত্রীকে বলবে “হিসাব বাতিল” — একটি ছোট কিন্তু বাস্তব bug. নিয়ম: যখন None আর অন্য “মিথ্যা” মান (0, "", []) আলাদা অর্থ বহন করে, তখন সরাসরি is None বা is not None লিখুন। None একটিই object, তাই এখানে == নয়, is — পর্ব ০৮-এর নিয়ম, আর PEP 8-এর সুপারিশও তাই।

Conditional expression — এক লাইনের সিদ্ধান্ত

গ্রেড-ক্যালকুলেটরের শেষে আর ভাড়ার শেষ রূপে আপনি দেখেছেন rate = 1 if is_student else 2. এটি একটি conditional expression — অনেকে বলেন Python-এর “ternary”. গঠন: সত্য_হলে_মান if শর্ত else মিথ্যা_হলে_মান. এটি একটি expression, অর্থাৎ একটি মান তৈরি করে — তাই =-এর ডান দিকে, print()-এর ভেতরে বা f-string-এ বসানো যায়। ক্রমটি খেয়াল করুন: C-র cond ? a : b-এর মতো শর্ত আগে নয়, মাঝখানে।

label = "পাস" if marks >= 33 else "ফেল"
unit = "টাকা" if amount != 1 else "টাকা মাত্র"
print(f"অবস্থা: {'অনলাইন' if connected else 'অফলাইন'}")

দুটি ছোট মানের মধ্যে একটি বাছাই, একটি সরল শর্ত — এখানে এক লাইন চার লাইনের if/else-এর চেয়ে পরিষ্কার।

grade = "A+" if m >= 80 else "A" if m >= 70 else "A-" if m >= 60 else "F"

এটা বৈধ Python, ঠিকমতো কাজও করে — কিন্তু একবার পড়ে কে বুঝবে? একাধিক conditional expression শিকলে জুড়লে, বা শর্ত ও মান লম্বা হলে, সাধারণ if/elif লিখুন। প্রশ্ন একটাই: “পরের মানুষ কি এক নজরে বুঝবে?”

pass — “এখানে এখনো কিছু নেই”

Python-এ block ফাঁকা রাখা যায় না। কিন্তু কাঠামো আগে লিখে পরে ভেতরটা ভরাতে চাইলে? তখন pass — একটি statement, যা কিছুই করে না, শুধু জায়গা দখল করে রাখে:

if user_type == "admin":
    pass            # TODO: অ্যাডমিন প্যানেল পরে বানাব
else:
    show_home()

তবে চূড়ান্ত কোডে pass দেখলে সন্দেহ করুন: কোনো ক্ষেত্র কি চুপচাপ উপেক্ষা হচ্ছে? “কিছু করার নেই” সত্যি হলে একটি comment দিয়ে কারণ লিখে রাখুন।

৬ · match-case — মান নয়, আকার মেলানো

Python 3.10 (২০২১ সালের অক্টোবর) থেকে ভাষায় এসেছে একটি নতুন সিদ্ধান্ত-কাঠামো: match statement, যার আনুষ্ঠানিক নাম structural pattern matching (PEP 634). প্রথম দেখায় এটি অন্য ভাষার switch-এর মতো লাগে। কিন্তু নামের “structural” শব্দটি খেয়াল করুন — এটি শুধু একটি মানকে কয়েকটি ধ্রুবকের সাথে তুলনা করে না, ডেটার গঠন মিলিয়ে দেখে, আর মিললে ভেতরের অংশগুলো নাম দিয়ে বের করে আনে।

গঠনটা এরকম: match-এর পর যে মান পরীক্ষা হবে (একে বলে subject), তারপর কয়েকটি case, প্রতিটিতে একটি pattern. Python subject-টি একবার হিসাব করে, তারপর ওপর থেকে নিচে প্রতিটি pattern-এর সাথে মেলায়। প্রথম যে pattern মেলে, তার block চলে — বাকিগুলো বাদ। elif-এর মতোই “প্রথম মিলটিই জেতে”, আর C-র switch-এর মতো পরের case-এ গড়িয়ে পড়া নেই, break-ও লাগে না।

Literal, | আর wildcard _ — যাত্রীর ধরন অনুযায়ী ভাড়া

match passenger:
    case "adult":
        rate = 2
    case "student":
        rate = 1
    case "child" | "senior":
        rate = 0
    case _:
        rate = None
        print("অজানা যাত্রীর ধরন:", passenger)
  • Literal pattern — "adult", 42, True, None: subject-এর সাথে সরাসরি তুলনা। string আর সংখ্যা == দিয়ে তুলনা হয়; True, False, None তুলনা হয় is দিয়ে।
  • OR pattern | — “এটা অথবা ওটা”। এখানে | কোনো bitwise operator নয়, শুধু pattern-এর বিকল্প জোড়ার চিহ্ন।
  • Wildcard _ — সবকিছুর সাথে মেলে, কিন্তু কোনো নাম বাঁধে না। এটি else-এর ভূমিকা নেয়, তাই সবার শেষে রাখুন। এর পরে আর কোনো case রাখলে Python SyntaxError দেয়, কারণ সেটি কখনো পৌঁছানো যাবে না।

Capture pattern আর guard — মান ধরে রাখা, তারপর শর্ত

Pattern-এ একটি সাধারণ নাম (যেমন x) লিখলে সেটি তুলনা করে না — যেকোনো মানের সাথে মেলে, আর সেই মানটি ওই নামে বেঁধে দেয়। একে বলে capture pattern. সাথে if জুড়ে দিলে পাওয়া যায় guard: pattern মেলার পরে একটি বাড়তি শর্ত, যা সত্য না হলে case-টি বাতিল হয়ে পরেরটিতে যায়। একটি টাকা পাঠানোর অ্যাপের উদাহরণ (সীমা ২৫,০০০ টাকা ধরা হয়েছে শুধু উদাহরণের জন্য):

match amount:
    case 0:
        print("কোনো লেনদেন নেই")
    case x if x < 0:
        print("ঋণাত্মক পরিমাণ — ভুল ইনপুট")
    case x if x > 25000:
        print(f"{x} টাকা সীমার বেশি — OTP লাগবে")
    case x:
        print(f"{x} টাকা পাঠানো হচ্ছে")

সত্যি বলতে, এই কাজটি if/elif দিয়েও সমান সহজে লেখা যেত। যখন সিদ্ধান্ত শুধু একটি সংখ্যার সীমা নিয়ে (গ্রেড, বিদ্যুৎ বিল, টাকার সীমা), তখন if/elif-ই স্বাভাবিক। match-এর আসল শক্তি দেখা যায় যখন ডেটার একটা আকার থাকে — list, dict, object. সেটাই পরের অংশ।

৭ · Sequence আর mapping pattern — একটি todo অ্যাপের কমান্ড পার্সার

ধরুন একটি ছোট টার্মিনাল todo অ্যাপ বানাচ্ছেন। ব্যবহারকারী লিখবেন add milk, done 2, বা list. পর্ব ০৯-এ দেখেছেন, "add milk".split() লেখাটিকে শব্দে ভেঙে একটি list দেয়: ["add", "milk"]. এখন প্রশ্ন — list-টির আকার কেমন, প্রথম শব্দ কী, আর বাকি শব্দগুলো কী? if দিয়ে লিখলে len(words) == 2 and words[0] == "add"-এর মতো শর্ত আর words[1]-এর মতো সূচক লাগত। Sequence pattern এই তিনটি প্রশ্ন একসাথে করে:

1match line.split():2    case ["list"]:3        show_all()4    case ["done", num]:5        mark_done(num)6    case ["add", item]:7        todos.append(item)8    case _:9        print("বুঝিনি")
Pattern মেলানো
subject
পরীক্ষা
item
todos
  1. Subject একবার হিসাব। line.split() চলে ["add", "milk"] দেয়। প্রতিটি case-এর জন্য আবার split হয় না — subject একবারই তৈরি হয়।
  2. ["list"] — দৈর্ঘ্য মেলেনি। এই pattern বলে “ঠিক একটি উপাদানের list, যা "list"”. আমাদের subject-এ দুটি উপাদান, তাই শব্দ দেখার আগেই বাতিল।
  3. ["done", num] — শব্দ মেলেনি। দৈর্ঘ্য ২, ঠিক আছে। কিন্তু প্রথম উপাদানটি literal "done" হতে হবে, আছে "add". বাতিল।
  4. ["add", item] — মিলেছে! দৈর্ঘ্য ২ ✓, প্রথমটি "add" ✓, আর দ্বিতীয় জায়গায় একটি capture নাম — সে যা পায় তাই ধরে: item = "milk". একটি লাইনে দৈর্ঘ্য-পরীক্ষা, তুলনা আর মান বের করা — তিনটিই হলো।
  5. Block চলে। todos.append(item) — তালিকায় "milk" যোগ হলো।
  6. বাকি সব বাদ। প্রথম মিলেই কাজ শেষ। case _ পরীক্ষাই হয়নি — সেটি থাকে “বাকি সবকিছু” ধরার জন্য, যেমন "dance" বা "add" একা লিখলে।

এবার পুরো পার্সারটি চালিয়ে দেখুন। এখানে আরও দুটি কৌশল আছে: *words “বাকি সব উপাদান” একটি list-এ ধরে (তাই add ডিম ১২টি-এর মতো কয়েক শব্দের কাজও চলে), আর guard দিয়ে যাচাই। সাতটি কমান্ড একটার পর একটা পাঠাতে শেষে একটি for লুপ ব্যবহার করেছি — লুপ পরের পর্বের বিষয়, এখানে শুধু জানুন এটি list-এর প্রতিটি লেখা দিয়ে handle একবার করে চালায়।

todos = []

def handle(line):
    match line.split():
        case ["add", *words] if words:
            todos.append(" ".join(words))
            return f"যোগ হলো (মোট {len(todos)})"
        case ["done", num] if num.isdigit() and 1 <= int(num) <= len(todos):
            return f"শেষ: {todos.pop(int(num) - 1)}"
        case ["done", num]:
            return f"{num} নম্বরে কোনো কাজ নেই"
        case ["list"]:
            return " | ".join(todos) or "(তালিকা খালি)"
        case _:
            return f"বুঝিনি: {line!r}"

for cmd in ["list", "add milk", "add ডিম ১২টি", "done 1", "done 9", "dance", "list"]:
    print(cmd, "→", handle(cmd))

আউটপুটের সাত লাইন মিলিয়ে দেখুন। প্রথম list-এ তালিকা ফাঁকা, তাই " | ".join([]) দেয় "" — একটি “মিথ্যা” মান — আর or তখন ডান পাশের "(তালিকা খালি)" দেয় (truthiness আর short-circuit একসাথে)। add milk ও add ডিম ১২টি-তে *words যথাক্রমে ["milk"] আর ["ডিম", "১২টি"] ধরে; guard if words নিশ্চিত করে যে শুধু add লিখলে এখানে ঢুকবে না। done 1 প্রথম কাজটি সরায়। done 9-এর ক্ষেত্রে প্রথম done-case-এর guard মিথ্যা (৯টি কাজ নেই), তাই case বাতিল হয়ে পরের ["done", num]-এ যায় — guard ব্যর্থ হলে Python পরের case-এ চলে যায়, এটাই দেখার বিষয়। dance কোনো pattern-এ মেলে না, ধরা পড়ে case _-এ। {line!r} লেখাটিকে কোটসহ দেখায়, যাতে ফাঁকা জায়গাও চোখে পড়ে।

একটি সূক্ষ্ম নিয়ম: sequence pattern string-এর সাথে মেলে না। match "ab":-এ case [a, b]: মিলবে না, যদিও string-কেও অক্ষরের ক্রম ভাবা যায়। নকশাকারীরা ইচ্ছা করেই এটি রেখেছেন, কারণ string-কে ভুল করে অক্ষরে ভেঙে ফেলা ছিল একটি পরিচিত bug-এর উৎস। তাই আগে .split() করে list বানিয়ে নিতে হয়।

Mapping pattern — dict-এর আকার মেলানো

অনলাইন সার্ভিসগুলো প্রায়ই JSON আকারে বার্তা পাঠায়, যা Python-এ আসে dict হয়ে (dict-এর পুরো গল্প পর্ব ১৬-এ, JSON পর্ব ২৬-এ)। Mapping pattern দেখে, নির্দিষ্ট চাবিগুলো আছে কি না, আর থাকলে মান বের করে:

match event:
    case {"type": "payment", "amount": amt}:
        print(f"{amt} টাকা জমা হলো")
    case {"type": "refund", "order": oid}:
        print(f"অর্ডার {oid}-এর টাকা ফেরত")
    case {"type": t}:
        print("অজানা ঘটনা:", t)
    case _:
        print("ভাঙা বার্তা")

খেয়াল করুন: mapping pattern-এ বাড়তি চাবি থাকলে আপত্তি নেই — {"type": "payment", "amount": 500, "via": "app"}-ও প্রথম case-এ মিলবে। শুধু উল্লেখ করা চাবিগুলো থাকতে হবে। (Sequence pattern উল্টো: সেখানে দৈর্ঘ্য হুবহু মিলতে হয়, যদি না *rest থাকে।)

Class pattern — এক ঝলক

Object-এর গঠনও মেলানো যায়: case Point(x=0, y=0): মানে “subject একটি Point, যার x আর y দুটোই শূন্য”। case int(): বা case str(): লিখে শুধু type-ও পরীক্ষা করা যায়। Class আর object শেখার পর (পর্ব ২৯), dataclass-এর পর্বে (পর্ব ৩২) এই class pattern আবার আসবে।

৮ · সবচেয়ে বড় ফাঁদ — case RED: তুলনা করে না, ধরে ফেলে

অন্য ভাষার switch-এর অভ্যাস থেকে অনেকে ধ্রুবকের নাম লিখে তুলনা করতে চান। ট্রাফিক বাতির একটি প্রোগ্রাম ভাবুন। কী হয়, ধাপে ধাপে দেখুন:

1RED = "red"2color = "blue"3match color:4    case RED:5        print("লাল বাতি — থামুন")6print(RED)
নামগুলো
RED
color
  1. একটি “ধ্রুবক”। RED = "red". বড় হাতের নাম দেখে আমরা ভাবি এটি ধ্রুবক — কিন্তু Python-এর কাছে এটি একটি সাধারণ ভ্যারিয়েবল।
  2. বাতি নীল। color-এর মান "blue". আমরা আশা করছি কিছুই ছাপা হবে না।
  3. Subject তৈরি। match color — subject হলো "blue".
  4. খালি নাম = capture! case RED:-এ RED একটি সাধারণ নাম, তাই এটি capture pattern. Capture pattern সবকিছুর সাথে মেলে, আর মানটি সেই নামে বেঁধে দেয়। ফলে RED এখন "blue"! আপনার “ধ্রুবক” নিঃশব্দে বদলে গেল।
  5. ভুল block চলল। নীল বাতিতে ছাপা হলো “লাল বাতি — থামুন”. কোনো error নেই।
  6. ক্ষতি ছড়িয়ে পড়ে। print(RED) দেখায় blue. এরপর প্রোগ্রামের যেখানেই RED ব্যবহার হবে, ভুল মান পাবে। সমাধান নিচে।

এই case-এর পরে আরও case থাকলে অবশ্য Python সাহায্য করে — চালানোর আগেই থামিয়ে দেয়:

SyntaxError: name capture 'RED' makes remaining patterns unreachable

অর্থাৎ “RED সবকিছু ধরে ফেলবে, তাই নিচের case-গুলোতে কখনো পৌঁছানো যাবে না”। কিন্তু ফাঁদের case-টি শেষ case হলে কোনো সতর্কবার্তা আসে না — ওপরের উদাহরণের মতো। সমাধান দুটি:

match color:
    case "red":
        print("থামুন")
    case "yellow":
        print("প্রস্তুত হন")
    case "green":
        print("চলুন")
    case _:
        print("অজানা বাতি:", color)

মান সরাসরি লিখলে সেটি literal pattern — তুলনা হয়, capture নয়।

from enum import Enum

class Light(Enum):
    RED = "red"
    GREEN = "green"

match signal:
    case Light.RED:
        print("থামুন")
    case Light.GREEN:
        print("চলুন")

নামের মাঝে একটি বিন্দু থাকলে (Light.RED, config.RED) Python সেটিকে value pattern ধরে, অর্থাৎ মানটির সাথে == দিয়ে তুলনা করে। Enum হলো নামযুক্ত ধ্রুবকের একটি দল — class-এর পর এটি আরও স্পষ্ট হবে।

মূল ধারণা

Pattern-এ খালি নাম (x, RED, item) মানে “যা পাও ধরে এই নামে রাখো”। বিন্দুওয়ালা নাম (Light.RED) বা literal ("red", 42) মানে “এর সাথে তুলনা করো”। _ মানে “যা পাও মেনে নাও, কোথাও রেখো না”। এই তিনটি পার্থক্য বুঝলেই match-এর অর্ধেক রহস্য শেষ।

match switch নয় — কখন কোনটি বাছবেন

পরিস্থিতিসবচেয়ে মানানসইকারণ
সংখ্যার সীমা (গ্রেড, বিল, বয়স)if/elifpattern দিয়ে সীমা লিখতে guard লাগে, বাড়তি জটিলতা
দুই-একটি ব্যতিক্রম বাদ দিয়ে মূল কাজguard clauseমূল পথ সোজা থাকে
একটি মান থেকে আরেকটি মান (যাত্রী → রেট)dict লুকআপডেটা আর কোড আলাদা, নতুন সারি যোগ সহজ (পর্ব ১৬)
ডেটার আকার মেলানো আর অংশ বের করা (কমান্ড, JSON, object)matchদৈর্ঘ্য, চাবি, type আর মান — এক pattern-এ

শেষ সারির কথাটি জরুরি। শুধু কয়েকটি string-কে একেকটি সংখ্যার সাথে জুড়তে match বা লম্বা elif লেখার দরকার নেই — RATES = {"adult": 2, "student": 1, "child": 0} আর RATES.get(passenger) যথেষ্ট। নতুন যাত্রীর ধরন এলে কোড নয়, শুধু ডেটায় একটি সারি যোগ হবে।

সবসময় “বাকি সব” ক্ষেত্রটি ভাবুন

প্রতিটি সিদ্ধান্তের পর নিজেকে জিজ্ঞেস করুন: “কোনো শর্তই না মিললে কী হবে?” else বা case _ না থাকলে অপ্রত্যাশিত মান চুপচাপ পার হয়ে যায় — হয়তো একটি ভ্যারিয়েবল তৈরিই হয় না, আর অনেক পরে গিয়ে NameError আসে, আসল কারণ থেকে বহু দূরে। ভালো অভ্যাস: শেষ শাখায় অন্তত একটি পরিষ্কার বার্তা দিন, আর যে ক্ষেত্র “কখনো ঘটা উচিত নয়” সেখানে error তুলে থামিয়ে দিন (raise, পর্ব ২৪)। একে বলে রক্ষণাত্মক ডিফল্ট — ভুল যত আগে, যত জোরে ধরা পড়ে, খুঁজে পাওয়া তত সহজ।

পরীক্ষা ও ইন্টারভিউতে
  • if/elif সারিতে একাধিক শর্ত সত্য হলে কোন block চলে? — শুধু ওপর থেকে প্রথম সত্য শর্তের block; বাকিগুলো পরীক্ষাই হয় না।
  • Python-এ block কীভাবে চিহ্নিত হয়? — কোলনের পর indentation দিয়ে (প্রথাগতভাবে ৪ space); কোঁকড়া বন্ধনী নেই।
  • Python-এর ternary কেমন? — a if cond else b; শর্ত মাঝখানে, এটি একটি expression.
  • match-এ কি fall-through হয়? — না; প্রথম মেলা case চলে, break লাগে না। _ হলো ডিফল্ট।
  • case RED: কেন বিপজ্জনক? — খালি নাম capture pattern; সবকিছুর সাথে মেলে আর RED-কে নতুন মান দেয়। Literal বা Color.RED-এর মতো dotted নাম লিখতে হয়।

৯ · AI-এর যুগে — AI-এর লেখা সিদ্ধান্ত পড়া ও যাচাই

AI সহকারী শর্তের কোড খুব দ্রুত লেখে, আর সেটা সাধারণত চলেও। সমস্যা “চলে কি না” নিয়ে নয় — সমস্যা হলো সব ক্ষেত্রে ঠিক চলে কি না, আর ছয় মাস পরে কেউ পড়ে বুঝবে কি না। শর্তের কোডে AI-এর কয়েকটি পরিচিত অভ্যাস:

AI প্রায়ই যা লেখেসমস্যাভালো বিকল্প
৪–৫ স্তর গভীর nested ifমূল কাজ হারিয়ে যায়, কোন else কার — বোঝা কঠিনguard clause দিয়ে সমতল করা
২০ লাইনের elif সারি, প্রতিটিতে শুধু একটি মান বসানোডেটা কোডের ভেতরে আটকা; নতুন মান যোগে কোড বদলাতে হয়dict লুকআপ (পর্ব ১৬)
সীমার শর্ত এলোমেলো ক্রমেনীরব bug — কিছু শাখা কখনো চলে নাকড়া শর্ত ওপরে; সীমার মান দিয়ে পরীক্ষা
match-এ case MAX_SPEED: বা case RED:capture — তুলনা হয় না, নাম নতুন মান পায়literal বা dotted নাম
else বা case _ নেইঅপ্রত্যাশিত ইনপুট চুপচাপ পার হয়শেষে স্পষ্ট বার্তা বা error
if not value: যেখানে 0 বৈধশূন্যকে “নেই” ধরে ফেলেif value is None:

AI-কে শর্তের কোড লিখতে বা পরীক্ষা করতে বললে নিয়মগুলো স্পষ্ট করে দিন, আর সীমার মান দিয়ে প্রমাণ চেয়ে নিন। নিচের কাঠামোটি কপি করে নিজের সমস্যায় বদলে নিন:

আমি Python 3.12 বা নতুন version ব্যবহার করি। নিচের নিয়মে একটি ফাংশন লিখে দাও: নম্বর (০–১০০) থেকে গ্রেড — ৮০+ A+, ৭০–৭৯ A, ৬০–৬৯ A-, ৫০–৫৯ B, ৪০–৪৯ C, ৩৩–৩৯ D, বাকিরা F. শর্ত: ১. nested if তিন স্তরের বেশি নয়; ভুল ইনপুট (০-এর কম, ১০০-এর বেশি) guard clause দিয়ে ফাংশনের শুরুতেই সামলাও। ২. শেষে একটি else রাখো, যাতে কোনো মান বাদ না পড়ে। ৩. match ব্যবহার করলে কোনো case-এ খালি নাম দিয়ে ধ্রুবকের সাথে তুলনা করবে না। ৪. সীমার মানগুলো (০, ৩২, ৩৩, ৭৯, ৮০, ১০০, ১০১, −১) দিয়ে একটি টেবিল দাও — প্রতিটির প্রত্যাশিত ফল। ৫. যদি এখানে if/elif-এর চেয়ে dict বা match ভালো হয়, কেন — এক লাইনে বলো।

AI-এর লেখা শর্তের কোড পেলে — যাচাইয়ের চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলো আপনাকে কোড-লেখক থেকে সিস্টেম-চিন্তক বানাবে।

প্র ০১প্রায় সব জনপ্রিয় ভাষা block বোঝাতে বন্ধনী ব্যবহার করে। Python কেন indentation বেছে নিল, আর এর দাম কী?

Guido van Rossum Python তৈরির আগে কয়েক বছর কাজ করেছিলেন ABC প্রকল্পে — নেদারল্যান্ডসের CWI-তে তৈরি একটি ভাষা, যার লক্ষ্য ছিল প্রোগ্রামার নন এমন মানুষকে প্রোগ্রামিং শেখানো। ABC-র নকশাকারীরা (Lambert Meertens, Leo Geurts প্রমুখ) একটি সরল পর্যবেক্ষণ থেকে শুরু করেছিলেন: ভালো প্রোগ্রামাররা বন্ধনী থাকলেও কোড সুন্দর করে সরিয়ে লেখেন, কারণ মানুষ কাঠামো চেনে চোখের আকার দেখে, বন্ধনী গুনে নয়। তাহলে একই তথ্য দুবার — একবার বন্ধনীতে মেশিনের জন্য, একবার indentation-এ মানুষের জন্য — লেখার দরকার কী? আর দুটো যদি কখনো আলাদা কথা বলে, তাহলে তো মানুষ আর মেশিন আলাদা প্রোগ্রাম পড়ছে!

Python এই চিন্তা নিয়েছে। Python-এর অফিসিয়াল Design FAQ-তে “Why does Python use indentation for grouping of statements?” প্রশ্নের উত্তরে Guido-র যুক্তি মোটামুটি এরকম: indentation-ই একমাত্র কাঠামো হলে কোড যেমন দেখায়, ঠিক তেমনই চলে; আর ভিন্ন ভিন্ন বন্ধনী-রীতি (বন্ধনী একই লাইনে না পরের লাইনে) নিয়ে তর্কও থাকে না। ফলে যেকোনো দুজনের Python কোড দেখতে অনেকটা একরকম, যা বড় দলে আর ওপেন-সোর্সে বিরাট সুবিধা।

দাম কী?

  • Whitespace এখন অর্থবহ: ইমেইল, চ্যাট বা কিছু ওয়েবসাইটে কোড কপি করলে space হারিয়ে যেতে পারে, আর তাতে প্রোগ্রামের অর্থ বদলে যায়। Tab আর space মিশলে বিভ্রান্তি — Python 3 তাই অস্পষ্ট মিশ্রণে TabError দেয়।
  • এক লাইনের lambda-র সীমা: indentation-ভিত্তিক ব্যাকরণে একাধিক statement-ওয়ালা ফাংশনকে expression-এর ভেতরে বসানো কঠিন; এজন্য Python-এর lambda শুধু একটি expression নিতে পারে (পর্ব ৩৮)।
  • টেমপ্লেট ও কোড-জেনারেশনে ঝামেলা: HTML-এর ভেতরে Python বসাতে বা স্বয়ংক্রিয়ভাবে Python কোড তৈরিতে indentation সামলাতে হয় সাবধানে।

বাস্তবে এই দামগুলো ছোট প্রমাণিত হয়েছে — আধুনিক editor নিজেই indentation সামলায়, আর YAML, Haskell, F#-এর মতো আরও ভাষা ও ফরম্যাট একই পথ নিয়েছে।

মূল উপলব্ধি: ভাষার নকশায় “একই তথ্য দুবার লেখা” মানে দুটো একসময় অমিল হওয়ার সুযোগ। Python সেই সুযোগটাই মুছে দিয়েছে — কোডের চেহারা আর কোডের অর্থ এক। ঝুঁকি কমেছে, বিনিময়ে whitespace-এর প্রতি একটু বেশি যত্ন লাগে।

প্র ০২২০১৪ সালে Apple-এর “goto fail” bug কী ছিল? বন্ধনী আর indentation-এর অমিল কীভাবে কোটি ডিভাইসের নিরাপত্তায় ফাটল ধরাল?

২০১৪ সালের ফেব্রুয়ারিতে Apple iOS ও macOS-এর জন্য একটি জরুরি নিরাপত্তা আপডেট প্রকাশ করে। কারণ ছিল তাদের SSL/TLS লাইব্রেরি (SecureTransport)-র একটি C ফাংশনে একটি অতিরিক্ত লাইন — যা পরিচিত হয় “goto fail” bug নামে (CVE-2014-1266). কোডটির কাঠামো ছিল মোটামুটি এরকম:

if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
    goto fail;

দ্বিতীয় goto fail; দেখতে প্রথমটির মতো সরানো, তাই চোখে মনে হয় সেটিও if-এর ভেতরে। কিন্তু C-তে বন্ধনী ছাড়া if শুধু ঠিক পরের একটি statement নিয়ন্ত্রণ করে। দ্বিতীয় লাইনটি তাই শর্তহীন — সবসময় চলে। আর সে সময় err-এর মান ছিল 0 (“সফল”), তাই ফাংশন “সব ঠিক আছে” বলে বেরিয়ে যেত, পরের ধাপের আসল যাচাই — সার্ভারের ডিজিটাল স্বাক্ষর পরীক্ষা — কখনো চলত না। ফলে একই Wi-Fi-তে থাকা একজন আক্রমণকারী নিজেকে ব্যাংক বা ইমেইল সার্ভার সাজিয়ে এনক্রিপ্ট করা সংযোগে আড়ি পাততে পারত।

লাইনটি কীভাবে এলো — কপি-পেস্ট, merge-এর ভুল — তা Apple কখনো প্রকাশ্যে বিস্তারিত বলেনি। কিন্তু শিক্ষাটা পরিষ্কার: মানুষ পড়েছে indentation, মেশিন পড়েছে বন্ধনী (বা তার অনুপস্থিতি)। দুটো আলাদা কথা বলেছে, আর কোড-রিভিউতে মানুষের চোখ মেশিনের অর্থ ধরতে পারেনি।

এই ঘটনার পর অনেক প্রতিষ্ঠান C-কোডিং নিয়মে “if-এ সবসময় বন্ধনী” বাধ্যতামূলক করে; GCC-তে -Wmisleading-indentation নামে একটি সতর্কবার্তা যোগ হয় (GCC 6, ২০১৬), যা ঠিক এই ধরনের বিভ্রান্তিকর indentation ধরে। Unreachable code-এর সতর্কবার্তাও কাজে লাগত — দ্বিতীয় goto-র পরের কোড কখনো চলত না।

Python-এ এই নির্দিষ্ট bug অসম্ভব: দ্বিতীয় লাইন if-এর মতো সরানো থাকলে সেটি সত্যিই if-এর ভেতরে। তবে মনে রাখুন, Python-এ উল্টো ভুল সম্ভব — একটি লাইন ভুল করে বাম দিকে সরে গেলে সেটি নিঃশব্দে block থেকে বেরিয়ে যায় (অংশ ২-এর সতর্কবার্তা)। কোনো নিয়মই ভাবনার বিকল্প নয়; টেস্ট (বিশেষ করে “ভুল স্বাক্ষর দিলে কি প্রত্যাখ্যান হয়?” ধরনের নেতিবাচক টেস্ট) এখানে আসল রক্ষাকবচ।

মূল উপলব্ধি: নিরাপত্তার বড় ফাটল প্রায়ই একটি ছোট সিদ্ধান্ত-লাইনে লুকিয়ে থাকে। যে ভাষায় চোখের দেখা আর মেশিনের অর্থ আলাদা হতে পারে, সেখানে সেই ফাঁক বন্ধ করতে নিয়ম, টুল আর টেস্ট — তিনটিই লাগে।

প্র ০৩Python কয়েক দশক switch statement যোগ করেনি — দুটি প্রস্তাব বাতিলও হয়েছে। তাহলে ২০২১-এ হঠাৎ match এলো কেন, আর সেটি switch-এর মতো নয় কেন?

Python-এ switch যোগ করার আনুষ্ঠানিক প্রস্তাব প্রথম আসে ২০০১ সালে — PEP 275 (Marc-André Lemburg). ২০০৬ সালে Guido নিজে লেখেন PEP 3103, Python 3-এর জন্য একটি switch-এর নকশা। দুটোই বাতিল হয়। PEP 3103-এর শেষে Guido উল্লেখ করেন, PyCon 2007-এর একটি জরিপে প্রস্তাবটির পক্ষে যথেষ্ট সমর্থন পাওয়া যায়নি।

কেন বাতিল? কয়েকটি কারণ বারবার এসেছে। প্রথমত, if/elif ইতিমধ্যে সব কাজ করতে পারে, আর একটি নতুন কাঠামো আনলে “একটি স্পষ্ট উপায়” নীতি দুর্বল হয়। দ্বিতীয়ত, switch-এর আকর্ষণ ছিল গতি — C compiler switch-কে jump table বানিয়ে দ্রুত করে। কিন্তু Python-এ case-এর মান কখন হিসাব হবে (compile-এর সময়, না ফাংশন সংজ্ঞায়িত হওয়ার সময়, না প্রতিবার?) — এ নিয়ে কোনো সমাধানই পরিষ্কার মনে হয়নি। তৃতীয়ত, শুধু মান থেকে কাজ বাছাইয়ের জন্য Python-এ ইতিমধ্যে একটি সুন্দর কৌশল ছিল: ফাংশনের dict.

তাহলে ২০২০-এ কী বদলাল? প্রশ্নটাই বদলেছিল। Brandt Bucher, Guido van Rossum, Tobias Kohn, Ivan Levkivskyi, Talin প্রমুখ যে প্রস্তাব আনলেন, তা আর “switch” ছিল না — ছিল structural pattern matching, যা functional ভাষাগুলোতে দশকের পর দশক প্রমাণিত। তিনটি PEP একসাথে: PEP 634 (নিয়ম), PEP 635 (কেন ও কীভাবে), PEP 636 (শেখার টিউটোরিয়াল)। ২০২১ সালের শুরুতে Python Steering Council প্রস্তাবটি গ্রহণ করে, আর Python 3.10-এ (অক্টোবর ২০২১) এটি আসে। এ পর্যায়ে আরেকটি প্রযুক্তিগত পরিবর্তনও সহায়ক ছিল: Python 3.9-এ নতুন PEG parser এসেছিল (PEP 617), যার ফলে match আর case-কে “soft keyword” রাখা সম্ভব হলো — অর্থাৎ পুরোনো কোডে match নামের ভ্যারিয়েবল থাকলেও ভাঙবে না।

নতুন প্রস্তাব switch-এর পুরোনো প্রশ্নগুলোর উত্তর দিল অন্যভাবে: এটি গতির প্রতিশ্রুতি দেয় না (pattern ওপর থেকে নিচে পরীক্ষা হয়), বরং একটি নতুন ক্ষমতা দেয় — নেস্টেড ডেটার গঠন একসাথে যাচাই ও বিশ্লেষণ, যা if দিয়ে লিখলে অনেক লম্বা ও ভঙ্গুর হয়। Parser, compiler, JSON বার্তা, কমান্ড-লাইন — এসব ক্ষেত্রে এর লাভ স্পষ্ট।

বিতর্ক অবশ্য থেমে থাকেনি। খালি নামের capture-ফাঁদ নিয়ে বহু সমালোচনা হয়েছিল, আর বিকল্প নকশা (যেমন PEP 640, 642) প্রস্তাবিত হলেও গৃহীত হয়নি।

মূল উপলব্ধি: একটি ফিচার বারবার বাতিল হওয়া মানে অনেক সময় প্রশ্নটা ভুলভাবে করা। “switch চাই” থেকে “গঠন মেলাতে চাই”-তে যেতেই একই সম্প্রদায় নতুন কাঠামোটি গ্রহণ করল।

প্র ০৪Pattern matching-এর শিকড় কোথায়? ML, Haskell আর Rust-এর match Python-এর থেকে কোথায় আলাদা?

Pattern matching-এর ধারণা এসেছে functional programming-এর জগৎ থেকে। ১৯৭০-এর দশকে এডিনবরায় Robin Milner-এর দল ML ভাষা তৈরি করে (মূলত একটি theorem prover-এর জন্য), আর সেখানে ফাংশন লেখা হতো ডেটার আকার ধরে ধরে — “list ফাঁকা হলে এটা, একটা মাথা আর বাকি অংশ হলে ওটা”। প্রায় একই সময়ে এডিনবরারই Rod Burstall-এর দলের NPL ও HOPE ভাষাতেও এই ধারা গড়ে ওঠে। ১৯৯০ সালে প্রকাশিত Haskell, পরে Erlang, OCaml, Scala, F#, Elixir — সবাই pattern matching-কে মূল হাতিয়ার বানায়। ২০১৫ সালে ১.০ হওয়া Rust-এ match এত কেন্দ্রীয় যে এরর সামলানো (Result) আর “মান থাকতেও পারে, না-ও পারে” (Option) — দুটোই এর ওপর দাঁড়ানো।

Python-এর সাথে বড় পার্থক্য — exhaustiveness: Haskell (সতর্কবার্তা চালু থাকলে), OCaml বা Rust-এর compiler জানে একটি type-এর সম্ভাব্য সব রূপ কী কী। কোনো রূপ বাদ পড়লে Rust কোড compile-ই হয় না — “None-এর ক্ষেত্রটি সামলানো হয়নি”। Python dynamic typing-এর ভাষা; চলার আগে সে জানে না subject-এ কী আসবে। তাই Python-এর match নিজে থেকে বলতে পারে না কোনো ক্ষেত্র বাদ পড়েছে কি না — সেজন্যই case _ বা রক্ষণাত্মক ডিফল্ট এত জরুরি। (mypy-এর মতো type checker কিছু ক্ষেত্রে, যেমন Enum-এর ওপর match, বাদ পড়া রূপ ধরতে পারে; type hint আর mypy পর্ব ৩৭-এ।)

আরেকটি পার্থক্য — statement বনাম expression: Rust, Haskell-এ match একটি expression, একটি মান ফেরত দেয়: let x = match n { ... }. Python-এর match একটি statement; মান চাইলে প্রতিটি case-এ ভ্যারিয়েবল বসাতে বা return করতে হয়।

তৃতীয় পার্থক্য — object-এর সাথে মিল: Python এসেছে OOP-এর জগৎ থেকে, তাই class pattern এখানে class-এর __match_args__ আর attribute ব্যবহার করে — algebraic data type-এর বদলে সাধারণ class আর dataclass-এর ওপর। এটি Scala-র “case class” আর “extractor”-এর ধারণার কাছাকাছি।

মূল উপলব্ধি: ভালো ধারণা এক ভাষা থেকে আরেক ভাষায় যায়, কিন্তু নতুন ঘরে এসে রূপ বদলায়। Python pattern matching নিয়েছে, কিন্তু static type-এর নিশ্চয়তা ছাড়া — তাই দায়িত্বের একটি অংশ প্রোগ্রামারের কাঁধে থেকে যায়।

প্র ০৫“Dangling else” সমস্যা কী? Python-এর indentation কীভাবে এটি পুরোপুরি মুছে দেয়, আর guard clause-এর ধারণা এর সাথে কীভাবে মেলে?

১৯৬০ সালের ALGOL 60 ভাষার নকশার সময় থেকেই একটি ব্যাকরণগত ধাঁধা পরিচিত: if a then if b then x else y. এখানে else-টি কার — বাইরের if a-র, না ভেতরের if b-র? দুটো পড়াই ব্যাকরণে বৈধ, আর অর্থ সম্পূর্ণ আলাদা। একে বলে dangling else — ঝুলে থাকা else. ALGOL 60 নিয়ম করে then-এর ঠিক পরে আরেকটি if বসানো নিষেধ করেছিল; Pascal আর C ঠিক করে “else সবসময় সবচেয়ে কাছের, এখনো else-হীন if-এর”। Parser লেখকদের কাছে এটি এতই পরিচিত যে yacc-এর মতো টুলে এটি “shift/reduce conflict”-এর পাঠ্যপুস্তকীয় উদাহরণ।

C-তে সমস্যাটি বাস্তবে এভাবে কামড়ায়:

if (logged_in)
    if (is_admin)
        delete_all();
else
    show_login();   /* দেখতে বাইরের if-এর, আসলে ভেতরের! */

লেখক ভেবেছেন লগইন না থাকলে লগইন পাতা দেখাবে। কিন্তু C নিয়মে else ভেতরের if (is_admin)-এর — ফলে লগইন করা সাধারণ ব্যবহারকারী লগইন পাতা দেখবেন, আর লগইন না থাকলে কিছুই হবে না।

Python-এ এই প্রশ্নই ওঠে না। else-কে ঠিক যে if-এর সমান সরানো রাখবেন, সে তারই। অস্পষ্টতা থাকার কোনো ব্যাকরণগত জায়গা নেই, কারণ indentation নিজেই গাছের কাঠামো। তবু nested if-এর গভীরতা বাড়লে মানুষের চোখে বিভ্রান্তি থেকে যায় — আর সেখানেই guard clause-এর ভূমিকা।

Martin Fowler-এর Refactoring (১৯৯৯; দ্বিতীয় সংস্করণ ২০১৮) বইয়ের “Replace Nested Conditional with Guard Clauses” কৌশলের মূল যুক্তি: শর্তের দুটি ধরন আছে — একটি যেখানে দুই পথই সমান স্বাভাবিক (তখন if/else), আর একটি যেখানে একটি পথ “স্বাভাবিক” আর অন্যটি “ব্যতিক্রম” (তখন ব্যতিক্রমটিকে guard করে আগে বিদায়)। পুরোনো structured programming-এর একটি নিয়ম ছিল “প্রতিটি ফাংশনের একটিই exit”; Fowler ও Kent Beck যুক্তি দেন, এই নিয়ম পড়ার সুবিধা না বাড়ালে মানার দরকার নেই। আজ বেশিরভাগ style guide আর linter (যেমন ruff-এর কিছু নিয়ম) অপ্রয়োজনীয় else-এর পর return ধরিয়ে দেয়।

মূল উপলব্ধি: ভাষার নকশা কিছু ভুল একেবারে অসম্ভব করে দিতে পারে (dangling else), কিন্তু বাকিগুলো — গভীর nesting, অস্পষ্ট পথ — সামলাতে লাগে লেখার অভ্যাস। ব্যাকরণ আর রুচি, দুটো মিলেই পরিষ্কার কোড।

অনুশীলন

এগুলোর বেশিরভাগে নতুন কোড লিখতে হবে না — পড়া, অনুমান করা আর মিলিয়ে নেওয়াই আসল কাজ।

  1. বিদ্যুৎ বিল হাতে হিসাব: অংশ ৪-এর electricity_bill ফাংশনে ৫০, ১৫০ আর ২৫০ ইউনিটের বিল কত হবে, খাতায় হিসাব করুন। তারপর ভাবুন: কেউ যদি শর্তগুলো উল্টো ক্রমে লেখে — আগে units <= 300, তারপর <= 200, তারপর <= 75 — তাহলে ৫০ ইউনিটে কোন সূত্র চলবে?

    ৫০ ইউনিট: প্রথম শর্ত সত্য, ৫০ × ৫ = ২৫০ টাকা। ১৫০ ইউনিট: দ্বিতীয় শর্ত, ৭৫ × ৫ + ৭৫ × ৭ = ৩৭৫ + ৫২৫ = ৯০০ টাকা। ২৫০ ইউনিট: তৃতীয় শর্ত, ৩৭৫ + ১২৫ × ৭ + ৫০ × ৮ = ৩৭৫ + ৮৭৫ + ৪০০ = ১৬৫০ টাকা।

    উল্টো ক্রমে ৫০ ইউনিট প্রথম শর্তেই (50 <= 300) আটকে যাবে, আর চলবে তৃতীয় স্তরের সূত্র: ৩৭৫ + ৮৭৫ + (৫০ − ২০০) × ৮ = ১২৫০ − ১২০০ = ৫০ টাকা — সম্পূর্ণ ভুল, অথচ কোনো error নেই। “ছোট সীমা আগে” নিয়মটি এখানে <=-এর জন্য; গ্রেডের >=-তে ছিল “বড় সীমা আগে”। দুটোর মূল কথা একই: সবচেয়ে কড়া শর্ত ওপরে।

  2. আউটপুট অনুমান: চালানোর আগে বলুন কী ছাপা হবে — x = 0; তারপর if x: print("A"), elif x is None: print("B"), elif x == 0: print("C"), else: print("D"). এরপর x = None আর x = [] দিয়ে আবার ভাবুন।

    x = 0: প্রথম শর্তে 0 “মিথ্যা”, তাই A নয়; 0 is None মিথ্যা; 0 == 0 সত্য — ছাপা হবে C.

    x = None: None মিথ্যা, তারপর None is None সত্য — B.

    x = []: ফাঁকা list মিথ্যা; [] is None মিথ্যা; [] == 0 মিথ্যা (list আর সংখ্যা কখনো সমান নয়) — তাই D. তিনটিই truthiness-এ “মিথ্যা”, কিন্তু আলাদা আলাদা শাখায় গেল — এজন্যই অর্থ আলাদা হলে সরাসরি পরীক্ষা লিখতে হয়।

  3. ফাঁদ খুঁজুন: একজন লিখেছেন — MAX = 100, তারপর match score: আর শুধু একটি case: case MAX: print("পূর্ণ নম্বর!"). score = 45 হলে কী ছাপা হবে, আর এরপর MAX-এর মান কত? দুটি উপায়ে ঠিক করুন।

    ছাপা হবে “পূর্ণ নম্বর!”, আর এরপর MAX-এর মান 45. কারণ MAX একটি খালি নাম — capture pattern — যা যেকোনো মানের সাথে মেলে আর সেটি MAX-এ রাখে। এটি একমাত্র (শেষ) case বলে Python কোনো SyntaxError-ও দেয়নি।

    সমাধান ১: literal লিখুন — case 100:. সমাধান ২: guard দিয়ে তুলনা — case s if s == MAX:; অথবা ধ্রুবকটি একটি module বা Enum-এ রেখে dotted নাম লিখুন (case limits.MAX:)। আর আসলে এখানে match-ই দরকার নেই: if score == MAX: সবচেয়ে সরল।

  4. কমান্ড পার্সার বাড়ান (কোড লিখুন): অংশ ৭-এর todo.py-তে দুটি নতুন কমান্ড যোগ করুন — clear (সব কাজ মুছে দেয়) আর rename 2 নতুন নাম (দুই নম্বর কাজের নাম বদলায়)। কোন pattern লাগবে, আর নতুন case-গুলো case _-এর আগে না পরে রাখবেন?

    দুটি নতুন case, অবশ্যই case _-এর আগে — নইলে _ সবকিছু ধরে ফেলবে, আর Python SyntaxError দেবে (“wildcard makes remaining patterns unreachable”):

    case ["clear"]:
        todos.clear()
        return "সব মুছে ফেলা হলো"
    case ["rename", num, *words] if num.isdigit() and words and 1 <= int(num) <= len(todos):
        todos[int(num) - 1] = " ".join(words)
        return "নাম বদলানো হলো"

    *words কয়েক শব্দের নতুন নাম ধরে; guard-এ words নিশ্চিত করে যে নতুন নাম ফাঁকা নয়, আর সীমা-পরীক্ষা ভুল নম্বর আটকায়। rename 9 x লিখলে guard মিথ্যা হবে, আর কমান্ডটি শেষে case _-এ “বুঝিনি” বার্তা পাবে — চাইলে done-এর মতো একটি আলাদা ভুল-বার্তার case যোগ করতে পারেন।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমPython একটি match statement চালানোর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. 🎯 Subject-এর মান একবার হিসাব করা
  2. 🔍 ওপরের প্রথম case-এর pattern মেলানো
  3. 🏷️ Pattern মিললে capture নামগুলোতে মান বসানো
  4. 🛡️ Guard থাকলে সেটি পরীক্ষা করা
  5. ▶️ সেই case-এর block চালিয়ে পুরো match থেকে বেরিয়ে যাওয়া

Python-এ m = 85 হলে নিচের কোড কী ছাপবে? if m >= 50: print("B") / elif m >= 80: print("A+") / else: print("F")

  • A+
  • B আর A+ দুটোই
  • B
  • F

Python-এ if-এর পরের লাইনটি সরানো (indent) না থাকলে সাধারণত কোন error আসে, আর কখন?

  • IndentationError, প্রোগ্রাম চলা শুরুর আগেই
  • NameError, ওই লাইনে পৌঁছালে
  • TypeError, শর্ত হিসাবের সময়
  • কোনো error নয়, Python block-টি ফাঁকা ধরে নেয়

Python-এ age = 20 হলে label = "প্রাপ্তবয়স্ক" if age >= 18 else "অপ্রাপ্তবয়স্ক"-এর পর label-এর মান কী?

  • "অপ্রাপ্তবয়স্ক"
  • True
  • SyntaxError, কারণ Python-এ ternary নেই
  • "প্রাপ্তবয়স্ক"

Python-এ RED = "red", তারপর match "green": আর একমাত্র case case RED: print("থামুন"). কী ঘটবে?

  • কিছুই ছাপা হবে না, কারণ "green" আর "red" আলাদা
  • "থামুন" ছাপা হবে, আর RED-এর মান হয়ে যাবে "green"
  • SyntaxError, কারণ খালি নাম case-এ লেখা যায় না
  • "থামুন" ছাপা হবে, সাথে একটি warning, আর RED অপরিবর্তিত থাকবে

Python-এ match "add tea biscuit".split():-এর জন্য কোন case প্রথমে মিলবে, যদি case-গুলো এই ক্রমে থাকে: ["add", item], ["add", *items], _?

  • ["add", item], item = "tea"
  • _
  • ["add", *items], items = ["tea", "biscuit"]
  • কোনোটিই নয়, কারণ sequence pattern list-এর সাথে মেলে না

একটি ফাংশন ভুল ইনপুটে None আর বৈধ ক্ষেত্রে একটি সংখ্যা (যা 0-ও হতে পারে) ফেরত দেয়। ফল r পরীক্ষার সবচেয়ে সঠিক উপায় কোনটি?

  • if r is None:
  • if not r:
  • if r == 0:
  • if len(r) == 0:

Python-এর match আর C-র switch-এর পার্থক্য সম্পর্কে কোনটি সঠিক?

  • match-এ প্রতিটি case-এর শেষে break লিখতে হয়
  • match শুধু পূর্ণসংখ্যার ধ্রুবক তুলনা করতে পারে
  • match-এ break না দিলে পরের case-এ গড়িয়ে পড়ে
  • match ডেটার গঠন মিলিয়ে অংশ বের করতে পারে, আর এতে fall-through নেই

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. if/elif/else: শর্ত ওপর থেকে নিচে পরীক্ষা হয়, প্রথম সত্য শর্তের block-ই চলে — তাই সবচেয়ে কড়া শর্ত ওপরে।
  2. Block চিহ্নিত হয় কোলন আর indentation দিয়ে (৪ space). ভুল করে বাম দিকে সরে যাওয়া লাইন নিঃশব্দে block থেকে বেরিয়ে যায়।
  3. গভীর nesting-এর বদলে guard clause: ব্যতিক্রম আগে বিদায়, মূল কাজ নিচে সোজা পথে। শেষে সবসময় “বাকি সব” ক্ষেত্রটি সামলান।
  4. if items: Pythonic, কিন্তু 0 বৈধ হলে is None লিখুন। a if cond else b ছোট বাছাইয়ে ভালো, শিকলে নয়।
  5. match (Python 3.10+) আকার মেলায়: literal, |, _, capture, guard, sequence, mapping, class. খালি নাম ধরে ফেলে, তুলনা করে না — literal বা dotted নাম লিখুন।

পরের পর্বে: সিদ্ধান্ত নিতে শিখলেন, এবার পুনরাবৃত্তি। for, range, enumerate, zip আর while দিয়ে একই কাজ বারবার করানো — আর লুপের ভেতরে আজকের if বসিয়ে বাছাই করা।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান