عندما يحدث خطأ ما
عندما لا تستطيع بايثون تنفيذ ما طلبته ترفع استثناءً: float("abc") ترفع ValueError، و{}["x"] ترفع KeyError، و1 / 0 ترفع ZeroDivisionError، وفتح ملف مفقود يرفع FileNotFoundError. وإن لم يعالجه شيء توقف البرنامج وطبع تتبّعًا (traceback) هو سلسلة الاستدعاءات التي أدّت إلى ذلك، ويُقرأ من الأسفل إلى الأعلى. وهذه هي النتيجة الصحيحة لخطأ برمجي حقيقي. أما للمشكلات المتوقعة، كسعر خاطئ يكتبه مستخدم، فتعالج الاستثناء بـtry وexcept.
# Handle an expected problem
def to_price(text):
try:
return float(text)
except ValueError:
return None
print(to_price("184.25")) # 184.25
print(to_price("abc")) # None
# An unhandled one stops the program with a traceback
# print(int("abc")) # ValueError: invalid literal for int()...التقط ما تتوقعه فقط
سمِّ نوع الاستثناء: except ValueError:. أما except: المجردة أو except Exception: فتبتلع أيضًا أخطاء لم تقصد إخفاءها، كـTypeError سببه تمرير None، ويستمر البرنامج ببيانات خاطئة. يمكن لعدة أنواع أن تشترك في معالج except (ValueError, KeyError): أو أن يكون لكل منها معالجه. تجرّب بايثون المعالجات بالترتيب وتنفّذ أول ما يطابق. ويمكنك الاحتفاظ بالخطأ بـexcept ValueError as error: وفحصه.
# Specific handlers, tried in order
def read_quantity(text):
try:
return int(text)
except ValueError as error:
print("not a whole number:", error)
return 0
except TypeError:
print("expected text, got something else")
return 0
print(read_quantity("200")) # 200
print(read_quantity("2.5")) # prints the message, then 0
print(read_quantity(None)) # prints the message, then 0else و finally
يكمل العبارة جزءان اختياريان. يعمل else: فقط إذا لم ترفع كتلة try شيئًا، مما يُبقي السطر الخطر قصيرًا ويُبقي الكود التالي خارج الحماية. أما finally: فيعمل دائمًا، حدث خطأ أم لا، حتى بعد return: استخدمه للتنظيف. وغالبًا ما تقوم كتلة with بالتنظيف عنك، كما في الملفات.
# else runs on success, finally runs always
def describe(text):
try:
price = float(text)
except ValueError:
print("bad price")
else:
print("price is", price)
finally:
print("done with", repr(text))
describe("184.25")
# price is 184.25
# done with '184.25'
describe("abc")
# bad price
# done with 'abc'رفع أخطائك الخاصة
الدالة التي تُعطى قيمة لا تقبلها يجب أن ترفض بوضوح بـraise، لا أن تُرجع بصمت شيئًا خاطئًا: raise ValueError("price must be positive"). اختر النوع المدمج المناسب (ValueError لنوع صحيح وقيمة سيئة، وTypeError لنوع خاطئ) واكتب رسالة تقول ما الخطأ. ثم يقرر المستدعي هل يلتقطه. وداخل كتلة except تعيد raise المجردة رفع الخطأ الذي التقطته للتو، وهذا مفيد حين أردت تسجيله فقط.
# Refuse bad input, let the caller decide
def parse_price(text):
price = float(text) # may raise ValueError itself
if not price > 0:
raise ValueError("price must be positive")
return price
for text in ["184.25", "-5", "abc"]:
try:
print(parse_price(text))
except ValueError as error:
print("rejected:", error)
# 184.25
# rejected: price must be positive
# rejected: could not convert string to float: 'abc'except الذي لا يفعل شيئًا (except: pass) انهيارًا كان يمكنك تصحيحه إلى أرقام خاطئة صامتة، وهذا أسوأ بكثير في كود التداول. التقط الخطأ فقط حيث تعرف استجابة معقولة: قيمة افتراضية أو تخطي العنصر أو إعادة المحاولة أو الإبلاغ ثم التوقف. وإلا فدعه ينتقل إلى مكان يعرف ما يفعل.try/except SpecificError: عالج المشكلات المتوقعة فقط.elseتعمل إن لم يُرفع شيء؛ وfinallyتعمل دائمًا.raise ValueError("message")يرفض المدخلات السيئة بوضوح.
التالي: الوحدات والاستيراد، كيف تعيد استخدام كود المكتبة القياسية وملفاتك الخاصة.
المختبر: ما الذي يُقيَّم
- حوّل النص دون انهيار باستخدام
safe_float25 نقطة - ارفض السعر السيئ باستخدام
parse_price25 نقطة - تخطَّ المدخلات السيئة باستخدام
first_valid_price25 نقطة - عالج ملفًا مفقودًا أو تالفًا باستخدام
read_quantity25 نقطة