זהו בוקר אפלולי וגשום של יום ראשון. השמיים אפורים ואתם במיטה מתחת לפוך המפנק שלכם, מתפללים שאתם עדיין בתוך החלום המתוק ההוא.
השעה היא 7:30. השעון המעורר מנגן שוב את השיר שפעם היה האהוב עליכם, והיום מעלה בכם אסוציאציות קשות שמערבות את הטלפון החכם שלכם ופטיש כבד מאוד.
הפגישה שלכם תתקיים בשעה 9:00, ואתם יודעים בוודאות שתספיקו להגיע בזמן אם תתעוררו בשעה 8:00 ותמהרו מאוד.
היד מושטת לכפתור ה"נודניק" שיפעיל שוב את השעון המעורר שלכם בעוד 10 דקות. ועוד פעם. ושוב.
אם נתאר את האלגוריתם שלפיו פעלתם, נוכל להגיד כך:
כל עוד השעון מצלצל, והשעה היא לפני 8:00, לחץ על כפתור הנודניק בשעון
.
נצייר את דרך הפעולה שלכם:
תרגול:
נסו לשרטט אלגוריתם להטלת 6 בקובייה.
כל עוד לא התקבל 6 בקובייה, הטילו את הקובייה מחדש.
כשקיבלתם 6 בקובייה, פִּצְחוּ בצהלולים בקול גדול.
המבנה ששרטטנו זה עתה נקרא לולאה.
נשתמש בלולאה כשנרצה לחזור על פעולה מספר פעמים שלאו דווקא ידוע לנו מראש.
אם ננסה לנתח את הלולאה כרעיון, נגלה שכל לולאה מורכבת מ־4 חלקים מרכזיים:
True
, גוף הלולאה ימשיך להתבצע.במקרה שלנו:
נסו לחשוב על דוגמה משלכם ללולאה כלשהי. פרקו אותה ל־4 הרעיונות המרכזיים שבהם דנו.
חשוב!
פתרו לפני שתמשיכו!
קל לחשוב על דוגמאות ללולאות מחיי היום־יום.
כמעט בכל פעם שאנחנו אומרים "עד ש־" או "כל עוד־", אנחנו בונים לולאה במציאות.
בכל פעם שאנחנו חוזרים על משהו שוב ושוב, אנחנו פועלים לפי לולאה מסוימת שמניעה אותנו.
רוב חיי היום־יום שלנו מתנהלים בלולאות, וזו הסיבה שלולאות הן כלי חזק כל כך בתכנות.
לפניכם כמה דוגמאות ללולאות:
תרגול: מצאו את 4 הרעיונות המרכזיים שעליהם דיברנו בכל אחת מהדוגמאות.
בסרט המוזיקלי Hans Christian Andersen מ־1952, מופיע השיר Inchworm, ושרים בו כך:
Two and two are four
Four and four are eight
Eight and eight are sixteen
Sixteen and sixteen are thirty-two
זה הזמן לכתוב Inchworm משלנו.
נשרטט איך כתיבת לולאה עבור שיר שכזה תיראה:
במקרה שלנו:
טוב, זה הזמן לקצת קוד, לא?
In [ ]:
current_number = 2
while current_number <= 16:
twice_number = current_number + current_number
print(f"{current_number} and {current_number} are {twice_number}")
current_number = twice_number
הקוד הזה משתמש במילת המפתח while
כדי ליצור לולאה.
הלולאה תואמת לחלוטין את תיאור השלבים המילולי שמופיע מעליה.
ננסה להיזכר איך נראית השורה הראשונה של השיר, וננסה להבין מה הקוד שנכתב למעלה אומר.
2 and 2 are 4
דבר ראשון, עלינו להכין את הסביבה לפני השימוש בלולאה.
נשתמש במשתנה שישמור עבורנו את הערך המספרי שיעמוד בראש השורה הנוכחית:
In [ ]:
current_number = 2
המספר שפותח את השורה האחרונה בשיר הוא 16, ולכן נרצה שהלולאה תרוץ כל עוד המספר הנוכחי ששמרנו קטן מ־16 או שווה לו.
נרשום את מילת המפתח while
, ואחריה ביטוי בוליאני שיקבע מתי גוף הלולאה ירוץ. נסיים בנקודתיים.
בכל פעם שהביטוי הבוליאני יהיה שווה ל־True
, גוף הלולאה ירוץ.
בפעם הראשונה (והיחידה) שהביטוי הבוליאני יהיה שקול ל־False
, גוף הלולאה לא יתבצע והתוכנית תמשיך לבצע את הקוד שנמצא אחרי הלולאה.
In [ ]:
while current_number <= 16:
אחרי שכתבנו את התנאי, זה הזמן לכתוב מה אנחנו רוצים שיתבצע בכל פעם שהתנאי יתקיים.
החלק הזה נקרא "גוף הלולאה", וכל הרצה שלו נקראת "אִיטֶרַצְיָה", או בעברית, "חִזְרוּר".
נתחיל בהגדרת המספר שיודפס בסוף השורה, שהוא המספר בתחילת השורה ועוד עצמו.
שימו לב להזחה, שמציינת שחלק הקוד הזה שייך ללולאת ה־while
ושהוא ירוץ בכל פעם שהביטוי הבוליאני שבראשה שקול ל־True
.
In [ ]:
twice_number = current_number + current_number
נדפיס את השורה עם הפרטים שיצרנו:
In [ ]:
print(f"{current_number} and {current_number} are {twice_number}")
לסיום, לקראת הדפסת השורה הבאה, נקדם את המשתנה שמכיל את הערך שמודפס בתחילת כל שורה בשיר.
הפעולה הזו תכין את המשתנה לשורה הבאה, וגם תקדם את הלולאה לסופה.
כיוון שתחילת כל שורה חדשה בשיר זהה לסוף השורה הקודמת, נוכל לרשום בפשטות:
In [ ]:
current_number = twice_number
כפי שראינו, לולאת while
משתמשת בביטוי בוליאני כדי להחליט אם להריץ קוד מסוים.
היא בודקת אם הביטוי הבוליאני שקול ל־True
, ואם כן, היא מריצה את קטע הקוד בגוף הלולאה.
כל עוד הביטוי הבוליאני המופיע ליד המילה while
שקול ל־True
, גוף הלולאה ימשיך לרוץ.
כשהביטוי יהפוך להיות שקול ל־False
, הלולאה תפסיק את ריצת הקוד בגוף הלולאה, והקוד שאחריה ימשיך לרוץ.
הרעיון של while
מקביל ל־if
שגופו רץ וחוזר לראש התנאי פעם אחר פעם, עד שהביטוי הבוליאני שבראש התנאי שקול ל־False
.
כתבו קוד שמקבל מהמשתמש מספר שלם גדול מ־1, ומדפיס את כל המספרים מ־1 ועד המספר שנקלט.
חשוב!
פתרו לפני שתמשיכו!
לפניכם דוגמה של קוד שמחשב את סכום כל המספרים הטבעיים, מ־1 ועד למספר שהזין המשתמש.
In [ ]:
def sum_positive_numbers(max_number):
total = 0
first_number = 1
while first_number <= max_number:
total = total + first_number
first_number = first_number + 1
return total
user_number = int(input("Please enter a number: "))
print(sum_positive_numbers(user_number))
הגדירו את 4 החלקים המופיעים בלולאה המופיעה בקוד מעלה.
שרטטו כיצד היא עובדת.
לפניכם קוד שמקבל כקלט את מספר התלמידים בכיתה.
לאחר מכן, הוא מקבל כקלט את הציון של כל תלמיד במבחן האחרון.
לבסוף, הקוד מחזיר את הציון הגבוה ביותר בכיתה.
שימו לב לשימוש שנעשה כאן בלולאות כדי לגשת למיקומי ערכים ברשימה.
In [ ]:
def get_grades(number_of_grades):
grades = []
while len(grades) < number_of_grades:
current_grade = int(input("Please enter a student grade: "))
grades = grades + [current_grade]
return grades
def get_highest_grade(grades):
highest_grade = grades[0]
current_grade_index = 1
while current_grade_index < len(grades):
if grades[current_grade_index] > highest_grade:
highest_grade = grades[current_grade_index]
current_grade_index = current_grade_index + 1
return highest_grade
number_of_grades = int(input("How many students are there?: "))
grades = get_grades(number_of_grades)
highest_grade = get_highest_grade(grades)
print(f"The highest grade is {highest_grade}")
חשבו על דרך לממש את הקוד הזה עם לולאה אחת בלבד.
In [ ]:
i = 1
j = 1
while i <= 10:
line = ''
while j <= 10:
line = line + str(i * j) + '\t'
j = j + 1
print(line)
j = 1
i = i + 1
הסבירו לעצמכם כיצד הקוד הזה עובד.
במידת הצורך, הזינו את הקוד ב־PythonTutor כדי לראות מה הוא עושה.
חשוב!
פתרו לפני שתמשיכו!
אם אתם חדשים בנושא הלולאות והתנסיתם בפתירת התרגילים, יש סיכוי לא רע שנתקעה לכם המחברת.
כשאנחנו מתעסקים עם לולאת while
, יש סיכון ממשי שניצור בטעות לולאה שלא תסתיים לעולם.
המצב שבו לולאה לא מסתיימת נקרא "לולאה אין־סופית", והוא נובע מכך שתנאי הלולאה שקול תמיד ל־True
.
ישנן שתי טעויות נפוצות שגורמות ללולאות להיות אין־סופיות.
זיהוי הטעות וטיפול בה יאפשרו ללולאה שלכם לעבוד כראוי:
False
.True
.
אם ליד תא במחברת שלכם מופיעה כוכבית ותאים אחרים לא יכולים לרוץ, סימן שאותו תא עדיין רץ.
אם הוא רץ זמן רב מדי, יש סיכוי שמדובר בלולאה אין־סופית. אם זה אכן המצב, בחרו בסרגל הכלים של המחברת ב־"Kernel" ואז ב־"Restart".
פעולה זו תעצור את הריצה של המחברת שלכם, ותאפשר לכם לתקן את הקוד הבעייתי ולהריץ אותו מחדש.
הנה דוגמה ללולאה אין־סופית, בתוכנה שמטרתה לספור מ־1 עד 10:
In [ ]:
i = 1
while i < 10:
print(i)
print("End of the program")
למה הלולאה הזו אין־סופית? תקנו אותה כך שתפעל כראוי.
המקרה ההפוך מלולאה אין־סופית הוא לולאה שפשוט לא רצה.
במילים אחרות – לולאה שתנאי הכניסה שלה שקול ל־False
בהרצתה הראשונה.
במקרה הזה, ראוי לבדוק כיצד אתחלנו את הסביבה, ואם התנאי שכתבנו אכן עובד.
In [ ]:
i = 8
while i <= 0:
print(i)
print("End of the program")
את הלולאה הזו כתב מתכנת מפוזר במיוחד, ויש בה יותר מבעיה אחת.
מצאו את הבעיות, תקנו אותן והריצו את התוכנית.
הפלט הרצוי, משמאל לימין, הוא: 8, 4, 2, 1.
זאת טעות נפוצה מאוד, עד כדי כך שיש לה שם ואפילו ערך בוויקיפדיה!
בשגיאה מסוג "סטייה באחד" (באנגלית: "Off By One") מתכנת שוכח לטפל במקרה האחרון, או מטפל במקרה אחד יותר מדי.
נראה דוגמה:
In [ ]:
numbers = [1, 2, 3, 4]
index = 0
total = 0
while index <= len(numbers):
total = total + numbers[index]
index = index + 1
print(total)
מה הבעיה פה? כיצד ניתן לפתור אותה?
לולאות הן כלי עוצמתי שמוסיף עניין רב לקוד.
עם זאת, לולאות עלולות להוסיף מקרים מיוחדים שגורמים לבאגים קשים לפענוח.
הדרך הכי טובה למצוא בעיות היא להדפיס את ערכם של המשתנים שנמצאים בלולאה ובאתחולי המשתנים שלפניה.
True
, גוף הלולאה ירוץ.
נתקעתם במסיבה שבה סופרים את השניות לאחור עד לכניסת השנה החדשה.
עזרו למשתתפים המבולבלים שהתחילו לספור מוקדם מדי –
קבלו את מספר השניות שנותרו עד חצות, והדפיסו עבורם את הספירה לאחור.
בסוף הספירה, הדפיסו "Happy new year!"
לדוגמה, עבור 4, הדפיסו:
4
3
2
1
Happy new year!
ציירו פירמידה עומדת על הצד, כך שראשה יהיה בצד ימין.
במהלך הקוד, קבלו מהמשתמש את אורך השורה שבה מצויר קודקוד הפירמידה.
לדוגמה: בפירמידה שלפניכם, המשתמש הכניס 5 כאורך השורה שבה מצויר קודקוד הפירמידה.
*
הצופן לכספת הביתית שלכם הוא 4812. בנו משחק בול־פגיעה שמאפשר למשתמש לנסות לנחש את הצופן.
למשתמש יש 3 ניסיונות לנחש נכונה את הקוד הסודי שלכם לפני שמופעלת אזעקה.
כחלק ממנגנון ההגנה מאיבוד הסיסמה לכספת, הכספת מציגה כמה ספרות נכונות המשתמש הזין אחרי כל ניחוש.
אפשרו למשתמש להזין קוד 3 פעמים, וכתבו לו בכל ניסיון כמה מתוך הספרות שהזין באמת קיימות בקוד הנכון, לאו דווקא בסדר שהקיש.
אם לא הצליח אחרי 3 ניסיונות, הדפיסו שהאזעקה הופעלה וסיימו את התוכנית.
לדוגמה, אם המשתמש הקיש בניסיון הראשון 0634, הדפיסו לו שרק אחת הספרות שניחש נכונה.
אם המשתמש הקיש בניסיון השני 1234, הדפיסו לו ש־3 ספרות תואמות לקוד המקורי.
אם המשתמש הקיש בניסיון השלישי 1284, הדפיסו לו ש־4 ספרות תואמות לקוד המקורי, ואז הדפיסו לו שהופעלה האזעקה.
אם המשתמש הקיש באחד הניסיונות 4812, הדפיסו שהכספת נפתחה בהצלחה וסיימו את התוכנית מייד.
השתמשו בלולאות.
נגדיר כלל: אם מספר הוא זוגי, נחלק אותו ב־2. אם מספר הוא אי־זוגי, נכפיל אותו ב־3 ונוסיף לו 1.
לפי השערת קולץ, אם ניקח מספר חיובי שלם ונשתמש עליו פעמים רבות בכלל הזה, תמיד נגיע בסופו של דבר למספר 1.
לדוגמה, אם ניקח את המספר 52, נקבל את שרשרת הפעולות הבאה:
$\ 52 \rightarrow 26 \rightarrow 13 \rightarrow 40 \rightarrow 20 \rightarrow 10 \rightarrow 5 \rightarrow 16 \rightarrow 8 \rightarrow 4 \rightarrow 2 \rightarrow 1$
כתבו פונקציה שמקבלת מספר, ומחזירה את מספר הפעולות שצריך לעשות עליו, לפי השערת קולץ, כדי להגיע ל־1.
לדוגמה: עבור המספר 52 היינו צריכים לבצע 11 פעולות כדי להגיע ל־1, ולכן עבור הקלט 52 הפונקציה תחזיר 11.
מצאו עבור איזה מספר בין 1 ל־1,000, צריך לעשות הכי הרבה צעדים, לפי השערת קולץ, כדי להגיע ל־1.
לדוגמה, הנה הצעדים שצריך לעשות עבור כל מספר עד 5:
מכאן שהמספר בין 1 ל־5 שעליו יש לעשות הכי הרבה צעדים, לפי השערת קולץ, עד שמגיעים ל־1, הוא 3.