איך נבדוק בפייתון שמשהו הוא מספר

14/08/2018

נתונה תוכנית פייתון קצרה המקבלת קלט ממשתמש וצריכה לוודא שהקלט הוא מספר. בואו בשביל המשחק נוסיף לו 7 ונדפיס את התוצאה:

x = input('please select a number: ')
print(float(x) + 7)

מה עושים אם המשתמשים שלכם לא כאלה נחמדים ומכניסים ערך שאינו מספר? הרצת התוכנית תיראה כך:

localhost:~ ynonperek$ python3 a.py
please select a number: yo
Traceback (most recent call last):
  File "a.py", line 2, in <module>
    print(float(x) + 7)
ValueError: could not convert string to float: 'yo'

ופייתון מתלונן בצדק שאי אפשר להמיר את yo למספר.

דרך אחת להתמודד עם הנושא היא לבדוק לפני ההמרה שאכן יש לכם ביד משהו שנראה כמו מספר. זה מה שהיינו עושים ב perl והפונקציה שם נקראה looks_like_number. כך זה היה נראה בפרל:

use strict;
use Scalar::Util qw/looks_like_number/;

print "please select a number: ";
my $x = <>;

if (looks_like_number($x)) {
  print($x + 7, "\n");
} else {
  print("Not a number\n");
}

לפייתון אין פונקציה looks_like_number וכל מיני ניסיונות למצוא דברים דומים יתנו לכם תוצאות לא נכונות. הנה למשל הפונקציה isnumeric שנראית ממש מתאימה:

>>> '1'.isnumeric()
True
>>> '15'.isnumeric()
True
>>> 'a'.isnumeric()
False

עד שעוברים לבדוק מספרים שליליים או כאלה עם נקודה עשרונית:

>>> '-5'.isnumeric()
False
>>> '1.2'.isnumeric()
False

מסתבר שפייתונאים מעדיפים גישה אחרת לגמרי - במקום לבדוק שמשהו יהיה בסדר לפני שעושים אותו אנחנו מעדיפים לנסות ולהתמודד אם דברים נשברו. במקרה של המרה למספר אין טעם לבדוק לפני זה שהערך נראה כמו מספר. אם הוא לא נראה כמו מספר ההמרה תיכשל ונוכל להתמודד עם זה. הפיתרון לכן נראה כך:

try:
    x = input('please select a number: ')
    print(float(x) + 7)
except ValueError:
    # value is not a number
    print("sorry not a number")

בפייתון Exception לא אומר שמשהו רע קרה וצריך להיפרד אלא בסך הכל מתאר מסלול שונה בקוד. תהיו נחמדים ל Exceptions שלכם והתוכניות שלכם יצאו נכונות וקריאות יותר.