תנאים – חלק 2

תנאים – תזכורת

ניזכר במחברת הקודמת, שבה למדנו על תנאים.
למדנו שבעזרת מילת המפתח if אנחנו יכולים לבקש מהקוד שלנו לבצע סדרת פעולות, רק אם תנאי כלשהו מתקיים.
במילים אחרות: אנחנו יכולים לבקש מקטע קוד לרוץ, רק אם ביטוי בוליאני מסוים שווה ל־True.

נראה דוגמה:


In [ ]:
shoes_in_my_drawer = int(input("How many shoes do you have in your drawer? "))

if shoes_in_my_drawer % 2 == 1:
    print("You have an odd number of shoes. Something is wrong!")

בקוד שלמעלה, ביקשנו מהמשתמש להזין את מספר הנעליים שיש לו, ואם המספר היה אי־זוגי הדפסנו לו שמשהו מוזר מתרחש.
אבל מה קורה אם נרצה להדפיס למשתמש הודעת אישור כשאנחנו מגלים שהכול בסדר?

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

חשוב!
פתרו לפני שתמשיכו!

מה אם לא?
על מילת המפתח else

דרך אחת לפתור את התרגיל שהופיע למעלה, היא זו:


In [ ]:
shoes_in_my_drawer = int(input("How many shoes do you have in your drawer? "))

if shoes_in_my_drawer % 2 == 1:
    print("You have an odd number of shoes. Something is wrong!")
if shoes_in_my_drawer % 2 != 1:
    print("You have an even number of shoes. Congratulations!")

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

פייתון מקנה לנו כלי נוח לבטא את ה"אחרת" הזה, כלי שמקל על הקריאוּת של הקוד – מילת המפתח else.
נראה איך אפשר לנסח את הקוד שלמעלה בעזרת else:


In [ ]:
shoes_in_my_drawer = int(input("How many shoes do you have in your drawer? "))

if shoes_in_my_drawer % 2 == 1:
    print("You have an odd number of shoes. Something is wrong!")
else:
    print("You have an even number of shoes. Congratulations!")

שימו לב לצורת ההזחה: ה־else אינו מוזח, אך התוכן שבתוכו כן.
נזכור גם ש־else קשור ל־if שלפניו, ומדבר על המקרה המשלים לתנאי שנמצא באותו if.
דרך נוספת לחשוב על else היא שקטע הקוד בתוך ה־else יתבצע אם תוצאתו של הביטוי הבוליאני שמופיע כתנאי של ה־if היא False.

דוגמאות לתנאים עם else

בדוגמאות הבאות, התנאי מופיע כך, והפעולות שיקרו בעקבותיו מופיעות כך.

  1. אם השעה היא לפני 20:00, שמור על תאורה גבוהה במסעדה. אחרת, עמעם את התאורה.
  2. אם הגיל של המשתמש הוא לפחות 18, אפשר לו להיכנס לבר. אחרת, הצע לו אטרקציות אחרות לבקר בהן וגם אל תכניס אותו.
  3. אם המשתמש בכספומט הזין סכום שלילי, או יותר מהסכום הזמין בחשבון שלו, הצג לו הודעת שגיאה. אחרת, הפחת לו את הסכום מהחשבון, הוצא לו שטרות בסכום שהזין.
  4. אם הדוד כבוי וגם השעה היא לפני 8:00 וגם השעה היא אחרי 7:00, הדלק את הדוד. אחרת, אם הדוד דלוקכבה את הדוד.

זרימת התוכנית: ציור לדוגמה

מימוש לדוגמה

התוכנית המוצגת פה מעט מורכבת יותר מהשרטוט המופיע למעלה, כדי לתת לה נופך מציאותי יותר.


In [ ]:
is_boiler_on = input("Is your boiler turned on? [yes/no] ")
hour = int(input("Enter the hour (00-23): "))
minute = int(input("Enter the minute (00-59): "))

if is_boiler_on == 'yes':
    is_boiler_on = True
else:
    is_boiler_on = False

if not is_boiler_on and hour == 7 and minute > 0:
    is_boiler_on = True
else:
    if is_boiler_on:
        is_boiler_on = False

if is_boiler_on:
    boiler_status = "on"
else:
    boiler_status = "off"

print("Boiler is " + boiler_status + " right now.")

מה המצב?
טיפול במצבים מרובים

בארצות הברית מדורגת מכירת אלבומים כך:

  1. אלבום מוזיקה נחשב "אלבום כסף" אם נמכרו ממנו לפחות 100,000 עותקים.
  2. אלבום מוזיקה נחשב "אלבום זהב" אם נמכרו ממנו לפחות 500,000 עותקים.
  3. אלבום מוזיקה נחשב "אלבום פלטינה" אם נמכרו ממנו לפחות 1,000,000 עותקים.
  4. אלבום מוזיקה נחשב "אלבום יהלום" אם נמכרו ממנו לפחות 10,000,000 עותקים.

קלטו את כמות העותקים שנמכרו עבור אלבום המטאל המצליח "רוצח או נזלת", והדפיסו את דירוג האלבום.
לדוגמה, אם המשתמש הכניס שמספר המכירות היה 520,196, הדפיסו "אלבום זהב".
אם האלבום לא נמכר מספיק כדי לזכות בדירוג, הדפיסו "האלבום אינו רב־מכר".

חשוב!
פתרו לפני שתמשיכו!

פתרון ושיפורים

בתרגיל שנתבקשתם לפתור, נוצר מצב שבו יש צורך בתנאים מרובים שמשלימים זה את זה.
נציג לפניכם שני פתרונות אפשריים:


In [ ]:
copies_sold = int(input("How many copies were sold? "))

# אנחנו משתמשים באותיות גדולות עבור שמות המשתנים האלו.
# זו מוסכמה בין מתכנתים שמבקשת להדגיש שערכי המשתנים הם קבועים, ולא הולכים להשתנות במהלך התוכנית.
SILVER_ALBUM = 100000
GOLD_ALBUM = 500000
PLATINUM_ALBUM = 1000000
DIAMOND_ALBUM = 10000000


if copies_sold >= DIAMOND_ALBUM:
    print("Diamond album")
else:
    if copies_sold >= PLATINUM_ALBUM:
        print("Platinum album")
    else:
        if copies_sold >= GOLD_ALBUM:
            print("Gold album")
        else:
            if copies_sold >= SILVER_ALBUM:
                print("Silver album")
            else:
                print("Your album is not a best-seller")

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


In [ ]:
copies_sold = int(input("How many copies were sold? "))

SILVER_ALBUM = 100000
GOLD_ALBUM = 500000
PLATINUM_ALBUM = 1000000
DIAMOND_ALBUM = 10000000

if copies_sold >= DIAMOND_ALBUM:
    print("Diamond album")
if copies_sold >= PLATINUM_ALBUM and copies_sold < DIAMOND_ALBUM:
    print("Platinum album")
if copies_sold >= GOLD_ALBUM and copies_sold < PLATINUM_ALBUM:
    print("Gold album")
if copies_sold >= SILVER_ALBUM and copies_sold < GOLD_ALBUM:
    print("Silver album")
if copies_sold < SILVER_ALBUM:
    print("Your album is not a best-seller")

הקוד נראה טוב יותר במידה ניכרת, אבל בכל if אנחנו בודקים שהתנאי שלפניו לא התקיים, וזה מסורבל מאוד.
אנחנו עושים את זה כדי למנוע הדפסה כפולה: אומנם כל אלבום זהב נמכר מספיק פעמים כדי להיות מוכתר כאלבום כסף, אבל לא נרצה להדפיס למשתמש את שתי ההודעות.

מה היה קורה אם לא היו תנאים אחרי האופרטור הלוגי and?
מחקו אותם, הכניסו לתוכנה כקלט 10000000 ובדקו מה התוצאה.

חשוב!
פתרו לפני שתמשיכו!

אם אחרת – elif

כדי לפתור את הבעיה שהוצגה למעלה, פייתון מעניקה לנו כלי נוסף שנקרא elif.
מדובר בסך הכול בקיצור של else... if (תנאי), או בעברית: אם התנאי הקודם לא התקיים, בדוק אם...
ראו, לדוגמה, איך נשפר את הקוד הקודם לקוד קריא יותר במידה רבה:


In [ ]:
copies_sold = int(input("How many copies were sold? "))

SILVER_ALBUM = 100000
GOLD_ALBUM = 500000
PLATINUM_ALBUM = 1000000
DIAMOND_ALBUM = 10000000

if copies_sold >= DIAMOND_ALBUM:
    print("Diamond album")
elif copies_sold >= PLATINUM_ALBUM:
    print("Platinum album")
elif copies_sold >= GOLD_ALBUM:
    print("Gold album")
elif copies_sold >= SILVER_ALBUM:
    print("Silver album")
else:
    print("Your album is not a best-seller")

מה קורה כאן?

הטריק הוא שבשורה שבה כתוב elif, פייתון תנסה לבדוק את התנאי רק אם התנאים שלפניו לא התקיימו.
במילים אחרות – ערכיהם של הביטויים הבוליאניים בכל התנאים שלפניו היו False.
בכל שורה שבה יש if או elif, פייתון בודקת האם הביטוי הבוליאני שבאותה שורה מתקיים, ואז:

  1. אם כן, היא מבצעת את הפעולות המוזחות מתחת לתנאי ומפסיקה לבדוק את התנאים הבאים.
  2. אם לא, היא עוברת לבדוק את התנאי ב־elif־ים הבאים (אם ישנם elif־ים).
  3. אם אף אחד מהתנאים לא מתקיים, יתבצע קטע הקוד ששייך ל־else (אם יש else).

ניתן לכתוב if בלי else ובלי elif־ים אחריו.
if תמיד יהיה ראשון, ואם יש צורך להוסיף מקרים, else תמיד יהיה אחרון, וביניהם יהיו elif־ים.

תרגול

כניסה לבנק, שלב 2

שם המשתמש שלי לבנק הוא wrong, והסיסמה שלי היא ads sports.
שם המשתמש של מנהל הבנק היא admin, והסיסמה שלו היא is trator.
קבלו מהמשתמש שם משתמש וסיסמה, והדפיסו לו הודעה שמספרת לו לאיזה משתמש הוא הצליח להתחבר.
אם לא הצליח להתחבר, הדפיסו לו הודעת שגיאה מתאימה.

חשבון למתחילים, שלב 1

דני רוצה ללמוד חשבון, ולצורך כך הוא צריך מחשבון פשוט שיעזור לו.
כתבו תוכנה שמקבלת 2 מספרים ופעולה חשבונית (+, -, *, / או **), ויודעת להחזיר את התשובה הנכונה לתרגיל.

לדוגמה:

  • עבור מספר ראשון 5, מספר שני 2 ופעולה / התוכנית תדפיס 2.5, כיוון ש־5/2 == 2.5.
  • עבור מספר ראשון 9, מספר שני 2 ופעולה ** התוכנית תדפיס 81, כיוון ש־92 == 81.
  • עבור מספר ראשון 3, מספר שני 7 ופעולה - התוכנית תדפיס -4, כיוון ש־3-7 == -4.

מחשבון מס הכנסה

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

  1. מי שמרוויח עד 6,310 ש"ח, משלם מס בשיעור 10% על הסכום הזה.
  2. מי שמרוויח עד 9,050 ש"ח, משלם מס בשיעור 14% על הסכום הזה.
  3. מי שמרוויח עד 14,530 ש"ח, משלם מס בשיעור 20% על הסכום הזה.
  4. מי שמרוויח עד 20,200 ש"ח, משלם מס בשיעור 31% על הסכום הזה.
  5. מי שמרוויח עד 42,030 ש"ח, משלם מס בשיעור 35% על הסכום הזה.
  6. מי שמרוויח עד 54,130 ש"ח, משלם מס בשיעור 47% על הסכום הזה.
  7. מי שמרוויח מעל הסכום האחרון, משלם מס בשיעור 50% על הסכום הזה.

הסכום תמיד משולם על ההפרש בין המדרגות.
לדוגמה, אם הרווחתי בחודש מסוים 10,000 ש"ח, תשלום המיסים שלי יחושב כך:
על 6,310 השקלים הראשונים אשלם 631 ש"ח, שהם 10% מאותה מדרגה.
על הסכום העודף עד 9,050 שקלים, שהוא 2,740 שקלים (9,050 - 6,310) אשלם 383.6 שקלים, שהם 14% מ־2,740 שקלים.
על הסכום העודף בסך 950 שקלים (10,000 - 9,050) אשלם 190 ש"ח, שהם 20% מ־950 שקלים.
בסך הכול, אשלם למס הכנסה באותו חודש 631 + 383.6 + 190 ש"ח, שהם 1,204.6 שקלים.

כתבו קוד למחשבון שמקבל את השכר החודשי שלכם ומדפיס את סכום המס שתשלמו.

ירוץ אם נתקן, אחרת...

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


In [ ]:
age = int(input("Please enter your age: ")))

if age < 0:
print("Your age is invalid."
if age < 18:
print("Younger than 18.")
else
print("You are so old!")