HomeCoursesPython
Chapter 12 of 14

এরর হ্যান্ডলিং

try, except, finally, raise & custom exception classes

এরর কী?

Python-এ program চলাকালীন দুই ধরনের সমস্যা হতে পারে — Syntax Error এবং Exception। Syntax error হলো code-এ ব্যাকরণগত ভুল, যা program run করার আগেই ধরা পড়ে। আর Exception হলো program চলার সময় ঘটে যাওয়া ত্রুটি।

Syntax Error বনাম Exception

# Syntax Error — program run-ই হবে না
if True
    print("Hello")   # SyntaxError: colon মিস!

# Exception — runtime-এ error হবে
x = 10 / 0           # ZeroDivisionError
int("abc")            # ValueError
my_list[100]          # IndexError

সাধারণ Exception Types

Exceptionকখন ঘটেউদাহরণ
ZeroDivisionErrorশূন্য দিয়ে ভাগ করলে10 / 0
ValueErrorভুল মানের ডেটা দিলেint("abc")
TypeErrorভুল type-এ operation করলে"2" + 3
IndexErrorlist-এ ভুল index দিলেlst[100]
KeyErrordictionary-তে নেই এমন key দিলেd["xyz"]
FileNotFoundErrorনেই এমন ফাইল পড়তে চাইলেopen("x.txt")
AttributeErrorনেই এমন attribute access করলে"hi".append()
NameErrorundefined variable ব্যবহার করলেprint(xyz)
🔑 Error Hierarchy বোঝা জরুরি
  • Python-এ সব exceptions BaseException class থেকে আসে
  • সাধারণ exceptions Exception class-এর sub-class
  • BaseExceptionExceptionValueError, TypeError, KeyError ইত্যাদি
  • Error hierarchy জানলে আপনি সঠিক level-এ error catch করতে পারবেন

try-except Block

Exception handle করার মূল হাতিয়ার হলো try-except block। try block-এ সম্ভাব্য error-যুক্ত code রাখা হয়, আর except block-এ error ঘটলে কী করতে হবে তা বলা হয়:

# Basic try-except
try:
    num = int(input("একটি সংখ্যা দিন: "))
    result = 100 / num
    print(f"ফলাফল: {result}")
except:
    print("কিছু একটা ভুল হয়েছে!")

# Specific exception ধরা (recommended)
try:
    num = int(input("একটি সংখ্যা দিন: "))
    result = 100 / num
    print(f"ফলাফল: {result}")
except ValueError:
    print("দয়া করে একটি সংখ্যা দিন, অক্ষর নয়!")
except ZeroDivisionError:
    print("শূন্য দিয়ে ভাগ করা যায় না!")

Exception Object ব্যবহার

as keyword দিয়ে exception object ধরে তার message দেখা যায়:

try:
    f = open("data.txt", "r")
    content = f.read()
except FileNotFoundError as e:
    print(f"ফাইল পাওয়া যায়নি: {e}")
    # Output: ফাইল পাওয়া যায়নি: [Errno 2] No such file or directory: 'data.txt'

try:
    ages = {"রহিম": 25, "করিম": 30}
    print(ages["জামাল"])
except KeyError as e:
    print(f"এই key নেই: {e}")
    # Output: এই key নেই: 'জামাল'

Multiple except ও else

একটি try block-এ একাধিক except দিয়ে বিভিন্ন ধরনের error আলাদাভাবে handle করা যায়। এছাড়া else clause দিয়ে error না হলে কী করতে হবে তাও বলা যায়:

# Multiple except + else
try:
    filename = input("ফাইলের নাম: ")
    with open(filename, "r") as f:
        data = f.read()
    number = int(data.strip())
except FileNotFoundError:
    print("ফাইল পাওয়া যায়নি!")
except ValueError:
    print("ফাইলে সংখ্যা নেই!")
except PermissionError:
    print("ফাইল পড়ার অনুমতি নেই!")
else:
    # শুধু তখনই চলবে যখন কোনো error হবে না
    print(f"ফাইল থেকে পড়া সংখ্যা: {number}")
    print(f"সংখ্যার বর্গ: {number ** 2}")
Blockকখন চলেব্যবহার
tryসবসময় (প্রথমে)সম্ভাব্য error-যুক্ত code রাখুন
exceptশুধু error হলেError handle করুন
elseerror না হলেসফল হলে কী করতে হবে
finallyসবসময় (শেষে)Cleanup code (ফাইল বন্ধ, connection close)

একটি except-এ একাধিক Exception

# Tuple দিয়ে একাধিক exception এক except-এ ধরা
try:
    value = int(input("সংখ্যা: "))
    result = 100 / value
except (ValueError, ZeroDivisionError) as e:
    print(f"ইনপুট সমস্যা: {e}")

# সাধারণ Exception class দিয়ে সব ধরা (শেষ resort)
try:
    # কিছু uncertain code
    risky_operation()
except Exception as e:
    print(f"অপ্রত্যাশিত সমস্যা: {type(e).__name__}: {e}")
💡 try-except মনে রাখার কৌশল

"TEFE" = Try → Except → Finally → Else
কিন্তু লেখার ক্রম হলো: tryexceptelsefinally
মনে রাখুন: "Try Except, Else Fine" — চেষ্টা করো, ব্যতিক্রম ধরো, নয়তো ভালো, এবং শেষে পরিষ্কার করো!

finally Block

finally block সবসময় চলে — error হোক বা না হোক, return statement থাকুক বা না থাকুক। এটি cleanup code-এর জন্য আদর্শ:

# finally — সবসময় চলে
try:
    f = open("data.txt", "r")
    data = f.read()
    result = int(data)
except FileNotFoundError:
    print("ফাইল নেই!")
    result = 0
except ValueError:
    print("ফাইলে ভুল ডেটা!")
    result = 0
else:
    print(f"সফলভাবে পড়া হয়েছে: {result}")
finally:
    # এই block সবসময় চলবে!
    print("Program শেষ হচ্ছে...")
    try:
        f.close()
        print("ফাইল বন্ধ করা হয়েছে")
    except NameError:
        pass  # f তৈরিই হয়নি মানে ফাইল খোলাই হয়নি

finally-এর বিশেষত্ব

# return-এর পরেও finally চলে!
def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return "ভাগ করা যায় না"
    finally:
        print("divide function শেষ!")  # সবসময় print হবে

print(divide(10, 2))
# Output:
# divide function শেষ!
# 5.0
🔑 finally vs with statement
  • ফাইল হ্যান্ডলিং-এর জন্য with statement ব্যবহার করুন — এটি internally finally ব্যবহার করে
  • Database connection, network socket ইত্যাদির জন্য finally দিয়ে cleanup নিশ্চিত করুন
  • try-finally (except ছাড়া) ব্যবহার করা যায় — শুধু cleanup নিশ্চিত করতে

raise Statement

raise keyword দিয়ে ইচ্ছামতো exception তৈরি (raise) করা যায়। এটি কখন দরকার? — যখন আপনি নিজে কোনো ভুল শর্ত শনাক্ত করেন এবং program-কে জানাতে চান:

# নিজে exception raise করা
def set_age(age):
    if age < 0:
        raise ValueError("বয়স নেতিবাচক হতে পারে না!")
    if age > 150:
        raise ValueError("বয়স ১৫০-এর বেশি হতে পারে না!")
    return age

try:
    user_age = set_age(-5)
except ValueError as e:
    print(f"ভুল: {e}")
    # Output: ভুল: বয়স নেতিবাচক হতে পারে না!

Re-raising Exception

কখনো কখনো exception catch করে কিছু কাজ (যেমন logging) করার পর আবার সেই exception-টিকে re-raise করতে হয়:

import logging

def process_data(data):
    try:
        result = int(data) * 2
        return result
    except ValueError:
        logging.error(f"ভুল ডেটা পাওয়া গেছে: {data}")
        raise  # একই exception আবার raise করো
        # অথবা: raise ValueError("ডেটা প্রসেস ব্যর্থ") from None

try:
    process_data("abc")
except ValueError as e:
    print(f"শেষ পর্যন্ত এখানে ধরা পড়লো: {e}")
raise Patternকাজব্যবহার
raise ValueError("msg")নতুন exception তৈরিInput validation
raiseবর্তমান exception re-raiseLogging-এর পরে
raise X from YException chainingমূল কারণ সংরক্ষণ
raise X from NoneChain ছাড়া নতুন exceptionমূল error লুকাতে

Custom Exceptions

Python-এ নিজের exception class তৈরি করা যায়। এটি Exception class থেকে inherit করতে হয়। Custom exceptions ব্যবহার করলে আপনার code আরো পরিষ্কার ও সুনির্দিষ্ট হয়:

# সহজ custom exception
class InvalidAgeError(Exception):
    """বয়স সংক্রান্ত ত্রুটি।"""
    pass

# বিস্তারিত custom exception
class InsufficientBalanceError(Exception):
    """ব্যালেন্স অপর্যাপ্ত হলে raise হবে।"""
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        self.deficit = amount - balance
        super().__init__(
            f"ব্যালেন্স অপর্যাপ্ত! বর্তমান: ৳{balance}, প্রয়োজন: ৳{amount}, ঘাটতি: ৳{self.deficit}"
        )

# ব্যবহার
class BankAccount:
    def __init__(self, name, balance=0):
        self.name = name
        self.balance = balance

    def withdraw(self, amount):
        if amount <= 0:
            raise ValueError("পরিমাণ ধনাত্মক হতে হবে!")
        if amount > self.balance:
            raise InsufficientBalanceError(self.balance, amount)
        self.balance -= amount
        return self.balance

# ব্যবহার
try:
    acc = BankAccount("রহিম", 1000)
    acc.withdraw(1500)
except InsufficientBalanceError as e:
    print(f"ত্রুটি: {e}")
    print(f"ঘাটতি: ৳{e.deficit}")
except ValueError as e:
    print(f"ভুল: {e}")

Exception Hierarchy তৈরি করা

# একটি project-এর জন্য exception hierarchy
class AppError(Exception):
    """Base exception — সব app error এখান থেকে আসবে।"""
    pass

class DatabaseError(AppError):
    """Database সংক্রান্ত সমস্যা।"""
    pass

class AuthenticationError(AppError):
    """Login/auth সমস্যা।"""
    pass

class PermissionDeniedError(AuthenticationError):
    """অনুমতি নেই।"""
    pass

# এখন AppError ধরলে সব ধরা পড়বে
try:
    raise PermissionDeniedError("Admin access প্রয়োজন")
except AuthenticationError as e:
    print(f"Auth সমস্যা: {e}")  # এটি ধরবে কারণ PermissionDenied হলো AuthenticationError-এর child
🔑 Custom Exception Best Practices
  • সবসময় Exception (বা তার sub-class) থেকে inherit করুন, BaseException থেকে নয়
  • Exception class-এর নাম Error দিয়ে শেষ করুন (যেমন: InvalidAgeError)
  • বড় project-এ একটি base exception তৈরি করে বাকি সব তা থেকে inherit করুন
  • __init__-এ extra attributes রাখলে error debugging সহজ হয়
💡 Error Handling মনে রাখার কৌশল

"SERF-C" = Specific except → Else block → Raise when needed → Finally cleanup → Custom classes
নিয়ম: সবসময় specific exception ধরুন, bare except: ব্যবহার করবেন না। Exception as e ব্যবহার করে error message দেখুন। কখনোই error গিলে ফেলবেন না (except: pass করবেন না)!

🧠 Quick Check
এই অধ্যায়ের মূল ধারণাগুলো যাচাই করুন — ৫টি প্রশ্নের উত্তর দিন:
Q1. Syntax Error ও Exception-এর মধ্যে মূল পার্থক্য কী?
✅ সঠিক উত্তর: খ) Syntax Error run করার আগে ধরা পড়ে, Exception runtime-এ ঘটে। Syntax error হলো code-এর গঠনগত ভুল যা Python parser ধরে ফেলে। Exception হলো runtime-এ ঘটা ত্রুটি যা try-except দিয়ে handle করা যায়।
Q2. try-except block-এ else clause কখন execute হয়?
✅ সঠিক উত্তর: গ) শুধু error না হলে execute হয়else block তখনই চলে যখন try block-এ কোনো exception raise হয় না। এটি সফল execution-এর পরবর্তী code রাখার জন্য আদর্শ।
Q3. finally block সম্পর্কে কোনটি সত্য?
✅ সঠিক উত্তর: গ) error হোক বা না হোক সবসময় চলেfinally block সবসময় execute হয় — error হলেও, return statement থাকলেও। এটি resource cleanup-এর জন্য ব্যবহার করা হয়।
Q4. Custom exception তৈরি করতে কোন class থেকে inherit করতে হয়?
✅ সঠিক উত্তর: খ) Exception। Custom exception সবসময় Exception class (বা তার sub-class) থেকে inherit করা উচিত। BaseException থেকে করা ঠিক নয় কারণ KeyboardInterrupt, SystemExit এগুলোও BaseException-এর child।
Q5. raise keyword (কোনো argument ছাড়া) কী করে?
✅ সঠিক উত্তর: গ) বর্তমান exception-টিকে আবার re-raise করেexcept block-এর ভেতরে শুধু raise লিখলে যে exception ধরা হয়েছিল সেটিই আবার raise হয়। এটি logging বা partial handling-এর পরে exception propagate করতে ব্যবহৃত হয়।
← Previous: ফাইল হ্যান্ডলিং Next: মডিউল ও লাইব্রেরি →