در این فصل چه یاد میگیری#
هر برنامهنویسی، از روزِ اول تا آخرِ عمر، خطا میگیرد. چیزی که تازهکار را از حرفهای جدا میکند این نیست که یکی خطا میگیرد و دیگری نه — این است که حرفهای در ده ثانیه میفهمد خطا چه میگوید. در این فصل یاد میگیری آن متنِ قرمزِ چندخطی را از کدام سرش بخوانی، شش خطای پرتکرارِ پایتون را از روی پیامشان بشناسی، و با try/except خطاهای قابلِپیشبینی را مدیریت کنی بدونِ اینکه خطاهای واقعی را پنهان کنی.

آخر این فصل میتوانی:
- یک
tracebackرا از پایین به بالا بخوانی و بگویی خطا کجا و چرا رخ داده - شش خطای رایجِ پایتون را از روی پیامشان تشخیص بدهی
- با
try/exceptیک خطای پیشبینیشده را مدیریت کنی - بگویی چرا
exceptبدونِ نامِ خطا یک اشتباهِ جدی است
قبل از شروع#
از فصل ۷: تابع، return، و اینکه تابع میتواند تابعِ دیگری را صدا بزند.
از فصل ۲ تا ۶: پیامهای TypeError، IndexError و KeyError را جستهگریخته دیدهای؛ اینجا مرتبشان میکنیم.
📓 نوتبوک: نوتبوک این فصل را در Colab باز کن — همهٔ کدهای این فصل آماده و بهترتیب داخلش هست.
۱. یک خطای واقعی، با تابع#
اول یک تابعِ سالم بساز:
def average(numbers):
"""میانگینِ یک فهرست عدد."""
return sum(numbers) / len(numbers)
print(average([10, 20, 30]))
20.0
حالا در یک سلولِ خالی همین تابع را با فهرستِ خالی صدا بزن:
print(average([]))
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[2], line 1
----> 1 print(average([]))
Cell In[1], line 3, in average(numbers)
1 def average(numbers):
2 """میانگینِ یک فهرست عدد."""
----> 3 return sum(numbers) / len(numbers)
ZeroDivisionError: division by zero
این همان چیزی است که traceback نامیده میشود. حجمش ترسناک است ولی ساختارش کاملاً منظم است.
۲. از پایین بخوانش#
قاعدهٔ طلایی: traceback را از خطِ آخر شروع کن.
خطِ آخر همیشه دو تکه دارد: نامِ خطا و توضیحش. اینجا ZeroDivisionError: division by zero — تقسیم بر صفر. در نود درصدِ موارد همین یک خط کافی است تا بفهمی چه شده.
اگر نبود، حالا به بالا نگاه کن. آن خطهای وسط، مسیرِ صدا زدن را نشان میدهند، از بیرونیترین به درونیترین:
Cell In[2], line 1— توprint(average([]))را صدا زدی.Cell In[1], line 3, in average— و داخلِ تابعِaverage، خطِ ۳، مشکل رخ داد.
فلشِ ----> دقیقاً روی خطی است که در هر مرحله مقصر بوده. پس درونیترین بلوک (پایینترین) جایی است که خطا واقعاً افتاد، و بالاترین بلوک جایی که تو شروعش کردی.
قبل از ادامه، جواب بده: خطای بالا در تابعِ average رخ داد. یعنی باگ حتماً در average است؟ جواب: نه لزوماً. average کارِ خودش را درست انجام داد؛ کسی فهرستِ خالی به آن داد. باگ میتواند اینجا باشد یا در صداکننده. traceback میگوید کجا منفجر شد، نه اینکه چه کسی فتیله را روشن کرد — و برای همین است که باید کلِ زنجیره را نگاه کنی، نه فقط خطِ آخر را.
۳. شش خطایی که بیشترین وقت را از تازهکارها میگیرند#
| پیام | یعنی چه | معمولاً بهخاطرِ |
|---|---|---|
SyntaxError |
پایتون اصلاً نتوانست جمله را بخواند | پرانتز یا گیومهٔ بستهنشده، دونقطهٔ جاافتاده |
IndentationError |
تورفتگی سرِ جایش نیست | بعد از دونقطه تورفته ننوشتی، یا Tab و فاصله قاطی شده |
NameError |
اسمی بهکار بردی که تعریف نشده | غلطِ املایی، یا سلولی که هنوز اجرا نکردهای |
TypeError |
این کار با این نوع تعریف نشده | جمعِ متن و عدد، یا تابعی که None برگردانده |
IndexError / KeyError |
جایگاه یا کلیدی خواستی که وجود ندارد | یکی بیشتر از طولِ فهرست، غلطِ املاییِ کلید |
ValueError |
نوع درست است ولی مقدار بیمعناست | int("سلام") — متن هست، ولی عدد نیست |
NameError در نوتبوک یک دلیلِ مخصوص هم دارد که در هیچ محیطِ دیگری نیست: سلولی که متغیر را میسازد هنوز اجرا نشده، یا اجرا شده و بعد پاکش کردهای. فصلِ ۱۰ کاملاً به همین اختصاص دارد.
۴. try / except: خطای پیشبینیشده را مدیریت کن#
بعضی خطاها باگاند و باید رفع شوند. بعضیها بخشِ عادیِ زندگیاند: دادهٔ واقعی خراب دارد و تو از قبل میدانی.
samples = ["12", "3.5", "سلام", ""]
for text in samples:
try:
value = int(text)
print(f"«{text}» → {value}")
except ValueError as error:
print(f"«{text}» → ValueError: {error}")
«12» → 12
«3.5» → ValueError: invalid literal for int() with base 10: '3.5'
«سلام» → ValueError: invalid literal for int() with base 10: 'سلام'
«» → ValueError: invalid literal for int() with base 10: ''
بلوکِ try کدی است که ممکن است بشکند؛ except ValueError یعنی «اگر دقیقاً این نوع خطا رخ داد، بهجای توقف این کار را بکن». آن as error خودِ شیء خطا را در دستت میگذارد تا بتوانی پیامش را چاپ کنی.
سه چیزِ آموزنده در این خروجی هست. اول اینکه "3.5" هم رد شد — int() عددِ اعشاریِ نوشتهشده بهصورتِ متن را نمیپذیرد و این تقریباً همیشه غافلگیرکننده است. دوم اینکه رشتهٔ خالی هم ValueError است نه صفر. سوم اینکه حلقه ادامه پیدا کرد — بدونِ try، همان ردیفِ دوم کلِ اجرا را متوقف میکرد.
✅ چک کن: هر چهار خط باید چاپ شوند. اگر فقط یک خط دیدی و بعدش traceback، یعنی
tryرا جا انداختهای یا تورفتگیاش داخلِ حلقه نیست.
📏 اندازه بگیر: حالا سؤالِ مهم: در دادهٔ واقعی، چند ردیف اینطوری رد میشود؟ اگر سه ردیف از هزار تا خراب باشد یک چیز است؛ اگر ششصد تا خراب باشد، ستون اصلاً آن چیزی نیست که فکر میکردی. عادت کن بهجای رد کردنِ ساکتِ خطاها، بشماریشان — و اگر شمارش بزرگ شد، بهجای مدیریتِ خطا برو داده را نگاه کن. این دقیقاً همان کاری است که در ترمِ ۲ فصلِ ۵ روی دادهٔ کثیفِ واقعی انجام میدهیم.
۵. except بدونِ نام: اشتباهی که گران تمام میشود#
پایتون اجازه میدهد بنویسی except: و هر خطایی را بگیری. تقریباً همیشه اشتباه است:
def risky_average(numbers):
try:
return sum(numbers) / len(numbers)
except:
return None
print(risky_average([10, 20, 30]))
print(risky_average([]))
print(risky_average("متن، نه فهرست"))
20.0
None
None
سه بار صدا زدیم و هیچوقت خطایی ندیدیم. ولی موردِ سوم یک باگِ واقعی بود: یک متن بهجای فهرستِ عدد داده شد، sum روی آن TypeError داد، و except: بیسروصدا قورتش داد و None برگرداند. حالا برنامهات دارد با یک مقدارِ غلط ادامه میدهد و تو خبر نداری.
نسخهٔ درست فقط همان خطایی را میگیرد که واقعاً انتظارش را داری:
def safe_average(numbers):
"""میانگین؛ برای فهرستِ خالی None. هر ورودیِ نامعتبرِ دیگری را عمداً رد نمیکند."""
try:
return sum(numbers) / len(numbers)
except ZeroDivisionError:
return None
print(safe_average([10, 20, 30]))
print(safe_average([]))
20.0
None
حالا فهرستِ خالی مدیریت میشود، ولی اگر کسی متن بدهد TypeError میگیرد و همانجا میفهمد.
⚠️ مواظب باش: قاعده را حفظ کن: فقط خطایی را بگیر که میدانی چرا رخ میدهد و میدانی با آن چه کنی. هر
exceptِ گشاد یک باگ را از امروز به فردا منتقل میکند — و فردا پیدا کردنش ده برابر سختتر است، چون دیگر traceback نداری.
🤖 از دستیارت بپرس: یک traceback واقعی را که خودت گرفتهای برایش بگذار و بپرس: «این traceback چه میگوید؟ خط به خط توضیح بده، ولی کد اصلاحی ننویس.» قیدِ آخر عمدی است. اگر بگذاری کد اصلاحشده بدهد، خطا را رفع میکنی بدونِ اینکه یاد بگیری؛ دفعهٔ بعد باز هم گیر میکنی. هدف این است که خودت بتوانی بخوانیاش.
واژههای تازهٔ این فصل#
| کلمه | تلفظ به حروف فارسی | یعنی چه |
|---|---|---|
| traceback | تریسبک | گزارشِ چندخطیِ خطا؛ مسیرِ صدا زدن از بیرون تا نقطهٔ انفجار |
| exception | اِکسپشِن | خطای زمانِ اجرا؛ چیزی که برنامه را متوقف میکند |
| try / except | ترای / اِکسپت | «این را امتحان کن» / «اگر این خطا شد، این کار را بکن» |
| ValueError | ولیو اِرور | نوع درست است ولی مقدار بیمعناست |
تمرینها
اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.
در فصل بعد#
حالا میتوانی خطا را بخوانی. ولی امروز یک ابزارِ دیگر هم داری که تقریباً همه استفادهاش میکنند: دستیارِ هوش مصنوعی. فصلِ بعد صریح دربارهٔ آن حرف میزند — نه با انکار و نه با تسلیم. یاد میگیری چطور از دستیار برای یاد گرفتن استفاده کنی، چه سؤالهایی واقعاً کمکت میکنند، و چرا کدی که نمیتوانی خطبهخط توضیحش بدهی، کدِ تو نیست.
به آخر این فصل رسیدی!
اگر ساختی و جواب داد، این دکمه مال توست.