زنجیرهٔ استثنا در Python میتواند علتِ اولیه را پشتِ خطایِ دامنه نگه دارد؛ آخرین خطِ traceback همیشه همهٔ ماجرا نیست. raise معمولی، raise from و raise from None سه رفتارِ یکسان ندارند. در تمرین این صفحه، یک خطایِ parseِ بیخطر را سهبار بستهبندی میکنیم و هم ویژگیِ شیء خطا و هم نمایشِ آن را واقعاً میخوانیم. هیچ رخدادِ واقعیِ سرویس بررسی نمیشود.
یک علتِ ثابت برای هر سه مسیر
ورودیِ ساختگی، رشتهٔ authored-not-a-number است که به int داده میشود و ValueError میسازد. کد فقط همین نوعِ مشخص را میگیرد و RuntimeError با پیامِ authored-domain-error میدهد. خطا به موفقیت یا مقدارِ خالی تبدیل نمیشود؛ تفاوتِ سه مسیر فقط نحوهٔ پیوندِ خطایِ دامنه به علت است.
برای ثابتبودنِ مثال و جلوگیری از ورودِ مسیرِ خصوصی به گزارش، کدِ کوچک با نامِ فایلِ خیالیِ authored_exception_fixture.py کامپایل میشود. در خروجیِ نمایش نیز frameِ بیرونیِ اجرای تمرین کنار گذاشته شده است. هیچ فایل، پایگاه، شبکه یا کلیدی برای ایجادِ خطا باز نمیشود؛ محتوای تمام tracebackها از همین fixture آمده است.
raise معمولی و context ضمنی
وقتی درون except، خطای جدید بدون from میدهیم، __context__ به ValueError قبلی اشاره میکند و __cause__ برابرِ None است. __suppress_context__ هم False میماند. نمایشِ استاندارد در این مسیر، ابتدا خطای parse و سپس جملهٔ مربوط به رخدادِ خطای دوم هنگامِ رسیدگی به خطای اول را نشان میدهد.
بنابراین دیدنِ RuntimeError در انتهای گزارش نباید باعث شود فرض کنیم برنامه اصلاً به تبدیلِ عدد نرسیده بود. context میتواند نشان دهد wrapper در حالِ رسیدگی به خطای دیگری بوده است. البته این رابطه بهتنهایی محلِ همهٔ اشکالهای سامانه را تشخیص نمیدهد؛ فقط رفتارِ همین شیء و همین اجراست.
raise from علت را صریح میکند
در شاخهٔ دوم، از raise RuntimeError(...) from original استفاده میکنیم. این بار __cause__ همان ValueError است و context نیز در این مثال به آن مربوط میماند. flagِ suppress_context برابرِ True میشود، اما نمایشِ خطایِ قبلی حذف نشده: علتِ صریح با جملهٔ direct cause دیده میشود.
| روشِ ساختگی | cause | context | suppress_context |
|---|---|---|---|
| raise ضمنی | None | ValueError | False |
| from original | ValueError | ValueError | True |
| from None | None | ValueError | True |
پس flag را مستقل از cause تفسیر نکنید؛ True در دو ردیف آخر، نمایشِ یکسان ایجاد نمیکند. کد هر سه tuple را با انتظارِ مستقل مقایسه میکند و وجودِ عبارتِ علتِ صریح را در خروجیِ همان شاخه میسنجد.
from None نمایش را عوض میکند، نه لزوماً شیء را
در شاخهٔ سوم، raise RuntimeError(...) from None اجرا میشود. در نمایشِ استانداردِ این نمونه، ValueError قبلی دیده نمیشود؛ اما __context__ هنوز شیء ValueError را دارد. بنابراین «در خروجی چاپ نشد» با «علت از حافظه پاک شد» یکی نیست. این تفاوت واقعاً در گزارشِ کد ثبت شده است.
از این نحو، پاکسازیِ خودکارِ اطلاعاتِ حساس نتیجه نمیگیریم. پیامِ خطایِ جدید هم میتواند دادهٔ نامناسب داشته باشد؛ logger یا کدِ دیگری ممکن است ویژگیها را جدا بخواند. برای خروجی عمومی، انتخابِ متن و فیلدهای مجاز باید مطابقِ سیاستِ همان برنامه انجام شود؛ from None بهتنهایی چنین سیاستی نیست.
کنترل را بر معنای خطا بنا کنیم
آزمون روی نوعِ cause و context و flag تکیه دارد، نه روی شمارهٔ خطِ ثابتِ یک فایلِ عملیاتی. قالب و خطهای traceback ممکن است با نسخه، مسیر و شیوهٔ اجرا فرق کنند. در این نمونه، نامها و مقدارها عمداً خیالیاند و کد کنترل میکند مسیرِ خصوصیِ دیسکهای C یا D واردِ متنِ ذخیرهشده نشده باشد.
نسخهٔ واقعیِ اجرا Python۳٫۱۲٫۱۴ است. سه wrapper مستقل و همان علتِ اولیه اجرا شدهاند؛ خروجیِ هر سه در JSON کامل قرار دارد. این تمرین تماس با ارائهدهندهٔ مدل، سیاستِ retry، خطای HTTP یا قطع اتصال را بازسازی نمیکند. نبودِ آن آزمایشها را با پیامِ ساختگیِ خطا پر نمیکنیم.
از علتِ فنی تا قراردادِ عمومی
قراردادِ خطایِ برنامه مشخص میکند caller چه کدِ دامنه و اطلاعاتِ مجازی دریافت کند. گزارشِ ممیزی هم حداقل شاهدِ لازم برای اقدام و نتیجه را تعریف میکند. این صفحه مرحلهٔ داخلِ زبان را توضیح میدهد؛ حفظِ علتِ فنی و نمایشِ عمومی دو تصمیمِ مرتبط اما جدا هستند.
برای ادامه در مبانی هوش مصنوعی، یک ورودیِ بیخطر و قابلِتکرار برای خطایِ adapter بسازید و نوعِ wrapper را صریح ثبت کنید. هیچ قابلیتِ خطایابی یا شکلِ exception در محصولِ اپرا از این کد استنباط نمیشود؛ هدف این است که خطایِ بستهبندیشده، علتِ اولیه را از نگاهِ بررسیکننده پنهان نکند.
فایل تمرین و منبع
کد کامل تمرینِ محلی و کنترلهای آن · نمونههای اصیل و نتیجهٔ اجرای واقعیِ همین کد
منابع در 2026-11-04 خوانده شدند؛ این تاریخ، تاریخ انتشار منبع نیست. مثالها و فایلهای این راهنما آموزشی و ساختهٔ تحریریهاند.