פונקציות שקוראות לפונקציות

פונקציות שקוראות לפונקציות#

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

בחנו את עצמכם

לנוחותכם חלונית עם הקוד שראינו בסרטון בpython tutor. מוזמנים להריץ בעצמכם:

בחנו את עצמכם

התבוננו בקטע הקוד הבא:

def max2(a, b):
    if a > b:
        return a
    else:
        return b

def max3(a, b, c):
    max_a_b = max2(a, b)
    max_all = max2(max_a_b, c)
    return max_all

def max4_v1(a, b, c, d):
    max_a_b_c = max3(a, b, c)
    max_all = max2(max_a_b_c, d)
    return max_all

בקטע זה מופיעות הפונקציות max2 ו-max3 אותן כבר ראינו. בנוסף, מוצגת הפונקציה max4_v1 המקבלת כקלט 4 מספרים ומחזירה את הגדול מביניהם. הפונקציה עובדת על פי דיאגרמת הבלוקים הבאה:

נניח שכעת אנחנו מבצעים את הפעולה max4_v1(7,13,0,42). ענו על השאלות הבאות:

עכשיו כשהצלחנו לממש את max3, נממש את max10 על-ידי קריאה לפונקציות העזר max2 וmax3.

לנוחיותכם חלונית עם הקוד שראינו בסרטון בpython tutor. מוזמנים להריץ בעצמכם:

בחלונית הקוד למטה מופיעים מימושים לפונקציות max2, max3 וmax4_v1 אשר פגשנו קודם. תזכורת: הפונקציה max4_v1 פועלת לפי הדיאגרמה הבאה:

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

דרישות מימוש - כפי שמופיע בדיאגרמה, חובה להשתמש בmax2 אך אסור להשתמש בmax3.

לאחר שסיימתם את המימוש, הריצו את התיבה ווודאו שעברתם את הבדיקות.

def max2(a,b):
    if a > b:
        return a
    else:
        return b

def max3(a,b,c):
    max_a_b = max2(a,b)
    max_all = max2(max_a_b, c)
    return max_all
    
def max4_v1(a,b,c,d):
    max_a_b_c = max3(a,b,c)
    max_all = max2(max_a_b_c, d)
    return max_all
    
def max4_v2(a,b,c,d):
    # delete pass and fill in your code below
    pass




### TESTS ###

print("********************")
print("Starting the test:")

print("********************")
print("Checking the maximum between 3, 7, 12, -20")
ans = max4_v2(3, 7, 12, -20)
if ans == 12:
    print("CORRECT: Very good, 12 is the maximal number")
else:
    print("WRONG: 12 is the maximal number but the code returned", ans)

print("********************")
print("Checking the maximum between -10, -20, -25, -12")
ans = max4_v2(-10, -20, -25, -12)
if ans == -10:
    print("CORRECT: Very good, -10 is the maximal number")
else:
    print("WRONG: -10 is the maximal number but the code returned", ans)
********************
Starting the test:
********************
Checking the maximum between 3, 7, 12, -20
WRONG: 12 is the maximal number but the code returned None
********************
Checking the maximum between -10, -20, -25, -12
WRONG: -10 is the maximal number but the code returned None

מודולריות קוד#

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

בשני המימושים השתמשנו ב”אבני בניין” בסיסיות על מנת לממש את הפונקציה max10. כלומר, השתמשנו בפונקציות אשר מוצאות ערך מקסימלי מבין 2, 3 ו-5 איברים, והרכבנו אותן כך שבסופו של דבר מצאנו באמצעותן את הערך המקסימלי מבין עשרת הערכים שבקלט.

התהליך שבו אנחנו מבצעים שינויים בתוכנה שלנו באמצעות החלפה של רכיבים ספציפיים לפי הצרכים שלנו מביא לידי ביטוי את תפיסת המודולריות (Modularity) שבכתיבת קוד. לפי תפיסה זו אנחנו יכולים לחשוב על הקוד אותו אנחנו כותבים כמורכב מרכיבי תוכנה נפרדים (באנגלית, Module, ומשם מגיע המונח) איתם אנחנו יכולים לשחק על מנת לממש תוכנות שונות. במקרה שלנו הרכיבים היו הפונקציות max2, max3, max5 ובאמצעות הרכבה שלהן בדרכים שונות מימשנו את הפונקציה max10.

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

  1. דלת הארון, אשר יכולה להיות מעץ מלא או מזכוכית

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

  3. רגלי הארון, אשר יכולות להיות בעלות תושבת קבועה או בעלות גלגלים

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

נשים לב כי על מנת לתמוך במודולריות הזאת, החלקים המקשרים בין הרכיבים צריכים להיות תואמים. לדוגמא, אם הצירים אשר מחברים בין גוף הארון והדלת בעלי חורים לשני ברגים, עלינו לוודא כי גם בדלת הזכוכית וגם בדלת העץ ישנם חורים לשני ברגים, אחרת לא נוכל לחבר אותן לארון. בדיוק באותו אופן, בשני המימושים לפונקציה max10 דאגנו להתאים בין הרכיבים הבסיסיים שלנו והאופן בו הם משתלבים במערכת. לפונקציית max5 נכנסים תמיד חמישה ערכים ואילו לפונקציית max3 נכנסים תמיד שלושה.

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