رفتن به محتوای اصلی
برنامه‌سازی پیشرفته با پایتون درس‌نامهٔ آزاد
درس متوسط ۳۰ دقیقه

خطا، اشکال‌زدایی و آزمون

استثناها و جریان انتشار، زمینه‌بان‌ها، روش اشکال‌زدایی، تست واحد و دابل‌های تست.

هدف این درس

بتوانی استثنای معنادار تعریف و منتشر کنی، با زمینه‌بان منبع را امن کنی و تست واحد بنویسی.

در این مطلب ۵

برنامهٔ حرفه‌ای با برنامهٔ تمرینی در همین‌جا فرق می‌کند: وقتی چیزی اشتباه پیش می‌رود، برنامهٔ خوب «تمیز و قابل فهم» می‌شکند، نه با Traceback بی‌ربط و حالت خراب.

خطا در برابر استثنا

خطای نحوی (SyntaxError) را مفسر قبل از اجرا می‌گیرد؛ استثنا (Exception) در زمان اجراست و می‌شود گرفتش. فلسفهٔ پایتون: «درخواست بخشش راحت‌تر از اجازه‌گرفتن است» (EAFP) — امتحان کن و استثنا را بگیر، به‌جای صد تا شرط احتیاطی.

class InsufficientFundsError(ValueError):
    """موجودی برای برداشت کافی نیست."""

def withdraw(balance, amount):
    if amount <= 0:
        raise ValueError("مبلغ باید مثبت باشد.")
    if amount > balance:
        raise InsufficientFundsError(f"موجودی {balance} برای برداشت {amount} کافی نیست.")
    return balance - amount

try:
    left = withdraw(100, 150)
except InsufficientFundsError as e:
    print("خطای دامنه‌ای:", e)
except ValueError as e:
    print("ورودی نامعتبر:", e)
else:
    print("موجودی باقی‌مانده:", left)
finally:
    print("ثبت در گزارش انجام شد.")

ترتیب except از خاص به عام است؛ وارونه بنویسی، شاخهٔ خاص هیچ‌وقت نمی‌رسد. else فقط وقتی اجرا می‌شود که استثنایی رخ نداده باشد — جای تمیزِ «مسیر موفقیت».

انتشار و مرز ترجمه

استثنا تا جایی بالا می‌رود که گرفته شود. قانون مرز: در لایهٔ پایین استثنای فنی، در مرز ماژول به استثنای دامنه‌ایِ قابل‌فهم برای کاربرِ آن لایه ترجمه‌اش کن. هرگز استثنا را قورت نده (except: pass)؛ یا مدیریتش کن یا بگذار بالا برود.

زمینه‌بان: منبع همیشه آزاد می‌شود

from contextlib import contextmanager

@contextmanager
def managed_resource(name):
    print(f"گرفتن {name}")
    try:
        yield name
    finally:
        print(f"آزادکردن {name}")

with managed_resource("قفل") as r:
    print("کار با", r)
# حتی اگر وسط کار استثنا بیاید، آزادسازی در finally اجرا می‌شود

روش اشکال‌زدایی

۱. بازتولید پایدار (کوچک‌ترین ورودی که خرابی را نشان می‌دهد). ۲. خواندن Traceback از پایین به بالا (آخرین خط نوع خطاست، بالای آن محل). ۳. فرضیهٔ واحد و آزمایش واحد. ۴. چاپ هدفمند یا breakpoint()، نه چاپ تصادفی در کل کد.

تست واحد

import unittest
from bank import withdraw, InsufficientFundsError

class TestWithdraw(unittest.TestCase):
    def test_normal(self):
        self.assertEqual(withdraw(100, 40), 60)

    def test_overdraft_raises(self):
        with self.assertRaises(InsufficientFundsError):
            withdraw(100, 150)

    def test_negative_rejected(self):
        with self.assertRaises(ValueError):
            withdraw(100, -10)

unittest استاندارد و بدون وابستگی است؛ pytest نگارش روان‌تر و اکوسیستم قوی‌تری دارد (assert ساده، فیکسچر، پارامتری). برای دانشجو: unittest را بفهم، و اگر پروژه جدی شد pytest را انتخاب کن — منطق تست‌نویسی (مرزها، استثناها، نام‌گذاری روشن) در هر دو یکی است.

سنجش فهم — خطا و تست

۰ از ۳ پاسخ داده شده

  1. ترتیب درست شاخه‌های except چگونه است؟
  2. بلوک else در try چه زمانی اجرا می‌شود؟
  3. قورت‌دادن استثنا با except خالی و pass کار قابل قبولی است.(درست / نادرست)

اول به همهٔ پرسش‌ها پاسخ دهید، بعد بررسی کنید.

مطالب مرتبط

از همین بخش و با برچسب‌های مشترک

این مطلب را خواندید؟ آن را علامت بزنید تا پیشرفت شما روی همین دستگاه ذخیره شود.

وضعیت پیشرفت برای خطا، اشکال‌زدایی و آزمون