טיפול בשגיאות – exeptions
עבודה עם תוכנה ללא טיפול בשגיאות משולה לניווט בסהרה, בלי מצפן, בלי מפה, בלי טלפון חכם, בלי מים, בלי אוכל, בלי רכב, נראה לי שהנקודה הובנה כבר במפה. בחיים זה נראה טריוויאלי אבל מה תוכנה צריכה לעשות כאשר אומרים לה לחסר 8 מתפוח, בואו ננסה את זה -
a="apple"
b=8
print(a-b)
>>>
TypeError: unsupported operand type(s) for -: 'str' and 'int'
פייתון שולחת לנו הודעת שגיאה מסוג TypeError (ויש עוד סוגים רבים) וגם הסבר שהאופרטור, במקרה שלנו פעולת החיסור, אינה תומכת בחיסור מספר ממחרוזת. כדאי לשים לב שפעולה כפל של מחרוזת במספר מתפרשת כשרשור של המחרוזת מספר פעמים ולא זורקת הודעת שגיאה.
ואיך התוכנה מגיבה אם מסנים למחוק איבר מטופל ?
tupla=(1,2,3,4) del tupla[1]
>>>
TypeError: 'tuple' object doesn't support item deletion
שוב TypeError לא ניתן למחוק איברים מטופל.
עכשיו בואו נעשה מה שתמיד חלמנו – נחלק באפס - תאכלי את זה המורה שרה!
x=3/0
print(x)
>>>
ZeroDivisionError: division by zero
נו. יש לו שגיאה משל עצמו.
למעשה הטקסט המלא של השגיאה הולך ככה בצנזור קל של שמות הקבצים בממחשב שלי –
Traceback (most recent call last):
File "C:…..", line 1, in <module> x=3/0
ZeroDivisionError: division by zero
כלומר, פייתון אומרת לנו באיזו שורת קוד התרחשה השגיאה, מה סוג השגיאה, והטקסט המסביר את השגיאה הספציפית.
עכשיו נדמיין שאנו צריכים לדעת את הגיל של מישהו על מנת לבדוק האם הוא יכול לעשות פעולה מסוימת התלויה בגיל, אנו מבקשים ממנו שיקליד את גילו והוא מקליד בטעות את שמו, מה קורה עם התוכנית שלנו ? כיצד נתקן את השגיאה ?
x=int(input("what is your age?")) if x>18: print("Enjoy") if x<=18: print("you are too young")
>>>
what is your age?
הבחור מקליד
Shalom
>>>
ValueError: invalid literal for int() with base 10: 'Shalom'
אנו מקבלים הודעה מסוג ValueError והתוכנה מפסיקה לעבוד – הבה נראה את הדרך של פייתון להתמודד עם המשבר –
try except
while True: try: x=int(input("what is your age?")) except ValueError: print("please enter a number") continue if x>18: print("Enjoy") break if x<=18: print("you are too young") break
what is your age?
שלום מקליד
shalom
>>>
please enter a number
what is your age?
שלום הבין את הטעות ומקליד
21
>>>
Enjoy
ראשית בנינו לולאת while כדי שתחזיר אותנו להתחלה במידה והבחור מתעקש שהגיל שלו צריך להיות באותיות, הלולאה הזו ממשיכה לנצח עד שהבחור מכניס מספר, ואז התוכנה מדפיסה את מה שהיא צריכה להדפיס ושוברת את הלולאה באמצעות פקודת break.
מה שמעניין יותר לעניינינו הוא המבנה של מנגנון לכידת הטעויות. במקרה הזה אנו צופים שהמתחכם עלול לעשות טעות מסוג ValueError לכן אנו בעצם אומרים לתוכנה לנסות (try) לקבל ממנו את התשובה הרצויה (מספר) ובמידה שלא קיבלה ויש לנו ValueError , ולמעשה ה- except שלנו מתממש, אנו מבקשים להדפיס הנחיה מתקנת למסך ולחזור לתחילת הלולאה באמצעות הפקודה continue .
חשוב לזכור – אנו לא מוגבלים ל- except אחד ולמעשה אנו יכולים אחרי ה- try להציב שורה של exceptions כל אחת מתייחסת לסוג אחר של טעות עם הנחיות מתאימות. יותר מזה, אנו יכולים לנסח הודעות שגיאה משל עצמנו. בואו נניח שבארץ הקדושה שלנו אסור להשתמש במספר 6 בשל קדושתו המיוחדת. הבה נבנה class של טעות בשם ErrorNumberSix וכמו כל הודעות השגיאה בפייתון גם הוא ירש תכונות מספריית בסיס המצויה בפייתון ונקראת Exception כך שהוא יפעל כמו הודעות שגיאה מובנות של פייתון –
הפקודה לזריקת הודעת שגיאה היא raise בצירוף שם השגיאה – נראה איך זה עובד –
class ErrorNumberSix(Exception): pass x=int(input("choose your number in life")) if x==6: raise ErrorNumberSix("you can't use the holy number 6")
>>>
choose your number in life
ברגע שהיא מקלידה את המספר 6 מתקבלת הודעת השגיאה (אחרי מיקום השגיאה ובלה בלה)–
ErrorNumberSix: you can't use the holy number 6
כמה דברים שאת צריכה לדעת – את התוכן הספציפי של הודעת השגיאה אנו יכולים לבחור מיד לאחר שאנו מבקשים לזרוק הודעת שגיאה באמצעות הפקודה raise, בתוך הסוגריים שאחרי שם השגיאה. שימי לב שאנו משתמשים בירושה וספריית הבסיס Exception מוכנסת כפרמטר במחלקה החדשה שבנינו לשגיאה שלנו.
שנית למה התוכנה משתמשת במספר 6 אם הוא קדוש ? אולי היתה מסתפקת ב- holy number J למה המחבר עבר לדבר בלשון נקבה? עזבי את זה.
השימוש בהודעת שגיאה באופן הזה, כשאנו יורשים את התכונות של ספריית הבסיס Exception, מאפשר למשל להודעה לפרט באיזו שורה התרחשה השגיאה.
finally
כפי שאמרנו, אפשר להכניס שורת try מתחתיה הקוד שאנו רוצים לבדוק. לאחר מכן except אחד או יותר ולבסוף, בין אם נלכד exception ובין אם לאו, אני יכולים לבקש, להריץ שורת קוד, שתרוץ בכל מקרה, תחת הביטוי finally – נראה דוגמא -
while True: try: x=int("abc") except ValueError: print("please enter a number") continue except SyntaxError: print("yalla gam ata") continue except TypeError: print("try again") finally: print("this line will always be here") break
>>>
please enter a number
this line willalways be here
יש לנו את הפקודה try שלתוכה אנו מכניסים את מה שאנחנו רוצים לבחון – במקרה למעלה אנו מנסים להפוך למספר את המחרוזת וזו שגיאה מסוג ValueError, לאחר מכן יש שרשרת של except תחת כל אחד הוראה מה לעשות אם השגיאה הנוצרת היא מהסוג שהזכרנו. לבסוף, תחת finally ישנה הוראה שתמיד יוצאת לפועל, הראיה לכך היא שיש בסופה פקודת break ששוברת את הלולאה while, שאם לא היתה יוצאת לפועל בכל מקרה, היינו ממשיכים לקבל בלי סוף את השורה please enter a number.