diff --git a/week2/3_Functions.ipynb b/week2/3_Functions.ipynb index a55b742..de75bee 100644 --- a/week2/3_Functions.ipynb +++ b/week2/3_Functions.ipynb @@ -1082,7 +1082,7 @@ "
\n",
"הצופן לכספת הביתית שלכם הוא 4812. בנו משחק בול־פגיעה שמאפשר למשתמש לנסות לנחש את הצופן.
\n",
"למשתמש יש 3 ניסיונות לנחש נכונה את המספר שלכם לפני שמתחילה אזעקה.
\n",
- "כחלק ממנגנון איבוד הסיסמה של הכספת, היא מציגה כמה ספרות נכונות המשתמש הזין אחרי כל ניחוש.
\n",
+ "כחלק ממנגנון ההגנה מאיבוד הסיסמה של הכספת, היא מציגה כמה ספרות נכונות המשתמש הזין אחרי כל ניחוש.
\n",
"אפשרו למשתמש להזין קוד 3 פעמים, וכתבו לו בכל ניסיון כמה מתוך הספרות שהזין באמת קיימות בקוד הנכון, לאו־דווקא בסדר שהקיש.
\n",
"אם לא הצליח אחרי 3 ניסיונות, הדפיסו שהאזעקה הופעלה וסיימו את התוכנית.
\n",
"
\n",
- " פייתון, בניגוד לבני אדם, מסתכל על תווים מיוחדים כמו \\n
או \\t
כתו אחד.
\n",
+ " פייתון, בניגוד לבני אדם, מסתכל על תווים מיוחדים כמו \\n
ו־\\t
כתו אחד.
\n",
" נסו לבדוק מה ה־len
שלהם כדי להיווכח בעצמכם.\n",
"
לולאות
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##הקדמה
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " זהו בוקר אפלולי וגשום של יום ראשון. השמיים אפורים, ואתם במיטה מתחת לפוך המפנק שלכם, מתפללים שאתם עדיין בתוך החלום המתוק ההוא.
\n",
+ " השעה היא 7:30. השעון המעורר מנגן שוב את השיר שפעם היה האהוב עליכם, והיום מעלה בכם אסוציאציות קשות שמערבות את הטלפון החכם שלכם ופטיש כבד מאוד.
\n",
+ " הפגישה שלכם בשעה 9:00, ואתם יודעים שתספיקו בוודאות להגיע אם תתעוררו בשעה 8:00 ותמהרו מאוד.
\n",
+ " היד מושטת לכפתור ה\"נודניק\" שיפעיל את השעון המעורר שוב עוד 10 דקות. ועוד פעם. ושוב.\n",
+ "
\n",
+ " אם נתאר את האלגוריתם שלפיו פעלתם, נוכל להגיד:
\n",
+ " כל עוד השעון מצלצל, והשעה היא לפני 8:00, לחץ על כפתור הנודניק בשעון.
\n",
+ " נצייר את דרך הפעולה שלכם:\n",
+ "
\n",
+ " תרגול:\n",
+ " נסו לשרטט אלגוריתם להטלת 6 בקובייה.
\n",
+ " כל עוד לא יצא 6 בקובייה, הטל את הקובייה מחדש.
\n",
+ " כשקיבלת 6 בקובייה, עשה צהלולים בקול גדול.\n",
+ "
הגדרה
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "המבנה ששרטטנו זה עתה נקרא לולאה.
\n",
+ "נשתמש בלולאה כשנרצה לבצע פעולה מסויימת מספר פעמים שאנחנו לאו־דווקא יודעים מראש.
\n",
+ "אם ננסה לפרק את הלולאה כרעיון, נגלה שכל לולאה מורכבת מ־4 חלקים מרכזיים:\n",
+ "
True
, גוף הלולאה ימשיך להתבצע.\n", + "במקרה שלנו:\n", + "
\n", + "\n", + " תרגול:\n", + " נסו לחשוב על דוגמה משלכם ללולאה כלשהי, ופרקו אותה ל־4 הרעיונות המרכזיים עליהם דנו.\n", + "
\n", + "דוגמאות
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "קל לחשוב על דוגמאות ללולאות מחיי היום־יום.
\n",
+ "כמעט כל פעם שאנחנו אומרים \"עד ש־\" או \"כל עוד־\", אנחנו בונים לולאה במציאות.
\n",
+ "כל פעם שאנחנו חוזרים על משהו שוב ושוב, אנחנו פועלים לפי לולאה מסוימת שמניעה אותנו.
\n",
+ "רוב חיי היום־יום שלנו מתנהלים בלולאות, וזו הסיבה שלולאות הן כלי כל כך חזק בתכנות.
\n",
+ "
\n", + "הנה כמה דוגמאות ללולאות:\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " תרגול:\n", + " מצאו את 4 הרעיונות המרכזיים שדיברנו עליהם בכל אחת מהדוגמאות.\n", + "
\n", + "כתיבת לולאה
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "בסרט המוזיקלי Hans Christian Andersen מ־1952, מופיע השיר Inchworm, ושרים בו כך:\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " Two and two are four" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " Four and four are eight
\n", + " Eight and eight are sixteen
\n", + " Sixteen and sixteen are thirty-two
\n", + "
\n",
+ "זה הזמן לכתוב Inchworm משלנו.
\n",
+ "נשרטט איך שיר כתיבת לולאה עבור שיר שכזה תראה:\n",
+ "
\n", + "במקרה שלנו:\n", + "
\n", + "\n", + "טוב, זה הזמן לקצת קוד, לא?\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "current_number = 2\n", + "while current_number <= 16:\n", + " twice_number = current_number + current_number\n", + " print(f\"{current_number} and {current_number} are {twice_number}\")\n", + " current_number = twice_number" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "הקוד הזה משתמש במילת המפתח while
כדי ליצור לולאה.
\n",
+ "הלולאה מקבילה לחלוטין לפירוט המילולי שנמצא מעליה.\n",
+ "
\n", + "ננסה להזכר איך נראית השורה הראשונה של השיר, וננסה להבין מה הקוד שנכתב למעלה אומר.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2 and 2 are 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n",
+ "דבר ראשון, עלינו להכין את הסביבה לפני השימוש בלולאה.
\n",
+ "נשתמש במשתנה שישמור לנו מה המספר שיתחיל את השורה הנוכחית:\n",
+ "
\n",
+ "המספר שפותח את השורה האחרונה בשיר הוא 16, ולכן אנחנו רוצים שהלולאה תרוץ כל עוד המספר הנוכחי ששמרנו קטן או שווה ל־16.
\n",
+ "נרשום את מילת המפתח while
, ומיד לאחריה נוסיף את הביטוי הבוליאני שכשהוא מתקיים אנחנו רוצים שתוכן הלולאה ירוץ. נסיים בנקודותיים.
\n",
+ "כל פעם שהביטוי הבוליאני יהיה שווה ל־True
, גוף הלולאה ירוץ ויבצע את מה שרצינו ממנו.
\n",
+ "בפעם הראשונה (והיחידה) שהביטוי הבוליאני יהיה שווה ל־False
, גוף הלולאה לא יתבצע והתוכנית תמשיך לבצע את הקוד אחרי הלולאה.
\n",
+ "
\n",
+ "אחרי שכתבנו את התנאי, זה הזמן לכתוב מה אנחנו רוצים שיתבצע כל פעם שהתנאי יתקיים.
\n",
+ "החלק הזה נקרא \"גוף הלולאה\", וכל ריצה שלו נקראת \"אִיטֶרַצְיָה\", או בעברית, \"חִזְרוּר\".\n",
+ "
\n",
+ "נתחיל בלהגדיר את המספר שיודפס בסוף השורה, שהוא המספר בתחילת השורה ועוד עצמו.
\n",
+ "שימו לב להזחה, שמציינת שחלק הקוד הזה \"שייך\" ללולאת ה־while
ויתבצע כל פעם שהביטוי הבוליאני בה יתקיים.\n",
+ "
\n", + "נדפיס את השורה עם הפרטים שיצרנו:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + " print(f\"{current_number} and {current_number} are {twice_number}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "ולסיום, לקראת הדפסת השורה הבאה, נקדם את המשתנה שמכיל את הערך שמודפס בתחילת שורה בשיר.
\n",
+ "הפעולה הזו תכין את המשתנה לשורה הבאה, וגם תקדם את הלולאה לסופה.
\n",
+ "מכיוון שתחילת כל שורה חדשה בשיר זהה לסוף השורה הקודמת, נוכל פשוט לרשום:\n",
+ "
סיכום ביניים
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "כפי שראינו, לולאת while
משתמשת בביטוי בוליאני כדי להחליט האם להריץ קוד מסוים.
\n",
+ "היא בודקת האם הביטוי שקול ל־True
, ואם כן, היא מריצה את קטע הקוד שכתוב בגוף הלולאה.
\n",
+ "כל עוד הביטוי הבוליאני המופיע ליד המילה while
שקול ל־True
, גוף הלולאה ימשיך לרוץ.
\n",
+ "כשהביטוי הופך להיות שקול ל־False
, הלולאה מפסיקה מיידית את הריצה שלה והקוד שאחרי הלולאה ממשיך לרוץ.\n",
+ "
\n",
+ "הרעיון של while
מקביל ל־if
שרץ וחוזר לראש התנאי פעם אחר פעם, עד שהביטוי הבוליאני שבראש התנאי שקול ל־False
.\n",
+ "
\n", + " תרגול:\n", + " כתבו קוד שמקבל מספר שלם מהמשתמש, ומדפיס את כל המספרים מ־1 ועד המספר שהמשתמש הכניס.\n", + "
\n", + "דוגמאות נוספות
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "####תרגילים חשבוניים
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "לפניכם דוגמה של קוד שמחשב את סכום המספרים כל המספרים הטבעיים, מ־1 ועד למספר שהוזן על־ידי המשתמש.
\n",
+ "\n",
+ "
\n",
+ " תרגול:\n",
+ " הגדירו את 4 החלקים המופיעים בלולאה המופיעה בקוד מעלה.
\n",
+ " שרטטו כיצד היא עובדת.\n",
+ "
מיקומים ברשימה
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "לפניכם קוד שמקבל את כמות החניכים בכתה.
\n",
+ "לאחר מכן, הוא קולט את הציון של כל תלמיד במבחן האחרון.
\n",
+ "לבסוף, הקוד יחזיר את הציון הגבוה ביותר בכתה.\n",
+ "
\n", + "שימו לב לשימוש שנעשה כאן בלולאות כדי לגשת למיקומים של ערכים ברשימה.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_grades(number_of_grades):\n", + " grades = []\n", + " while len(grades) < number_of_grades:\n", + " current_grade = int(input(\"Please enter a student grade: \"))\n", + " grades = grades + [current_grade]\n", + " return grades\n", + "\n", + "\n", + "def get_maximum(grades):\n", + " maximum_grade = grades[0]\n", + " current_grade_index = 1\n", + " while current_grade_index < len(grades):\n", + " if grades[current_grade_index] > maximum_grade:\n", + " maximum_grade = grades[current_grade_index]\n", + " current_grade_index = current_grade_index + 1\n", + " return maximum_grade\n", + "\n", + "\n", + "number_of_grades = int(input(\"How many students are there?: \"))\n", + "grades = get_grades(number_of_grades)\n", + "maximum_grade = get_maximum(grades)\n", + "print(f\"The maximum grade is {maximum_grade}\") " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " תרגול:\n", + " חשבו על דרך לממש את הקוד הזה עם לולאה אחת בלבד.\n", + "
\n", + "לולאה בתוך לולאה
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "i = 1\n", + "j = 1\n", + "while i <= 10:\n", + " line = ''\n", + " while j <= 10:\n", + " line = line + str(i * j) + '\\t'\n", + " j = j + 1\n", + " print(line)\n", + " j = 1\n", + " i = i + 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " תרגול:\n",
+ " אל תתקדמו הלאה עד שהצלחתם להסביר לעצמכם איך הקוד הזה עובד.
\n",
+ " במידת הצורך, השתמשו ב־PythonTutor כדי להזין את הקוד ולראות מה הוא עושה.\n",
+ "
לולאה אינסופית
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " אם אתם חדשים ללולאות והתנסיתם בפתירת התרגילים, יש סיכוי לא רע שנתקעה לכם המחברת.
\n",
+ " כשאנחנו מתעסקים עם לולאת while, יש סיכון ממשי שניצור בטעות לולאה שלא תסתיים לעולם.
\n",
+ " המצב שבו לולאה לא תסתיים נקרא \"לולאה אינסופית\", והוא נובע מכך שתנאי הלולאה שקול תמיד ל־True
.\n",
+ "
\n",
+ " ישנם שני מקרים מאוד נפוצים שגורמים ללולאות אינסופיות.
\n",
+ " טיפול במקרה הרלוונטי יגרום ללולאה שלכם לעבוד כראוי:\n",
+ "
False
.True
.\n",
+ " אם ליד תא במחברת שלכם מופיעה כוכבית ותאים אחרים לא יכולים לרוץ, סימן שהתא המדובר עדיין רץ.
\n",
+ " אם הוא רץ זמן רב מדי, יש סיכוי שמדובר בלולאה אינסופית. במידה וזה המצב, בחרו בסרגל הכלים של המחברת \"Kernel\" ואז \"Restart\".
\n",
+ " זה אמור לעצור את הריצה של המחברת שלכם, ולאפשר לכם לתקן ולהריץ מחדש את הקוד הבעייתי.\n",
+ "
\n", + " הנה דוגמה ללולאה אינסופית, בתוכנה שאמורה לספור מ־1 עד 10:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "i = 1\n", + "while i < 10:\n", + " print(i)\n", + "print(\"End of the program\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " תרגול:\n", + " למה הלולאה הזו אינסופית? עשו מה שצריך על־מנת לתקן אותה.\n", + "
\n", + "הלולאה לא רצה
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "המקרה ההפוך מלולאה אינסופית הוא לולאה שפשוט לא רצה. במילים אחרות – לולאה שתנאי הכניסה שלה שקול ל־False
בהרצתה הראשונה.
\n",
+ "במקרה הזה, ראוי לבדוק איך איתחלנו את הסביבה, והאם התנאי שכתבנו אכן עובד.\n",
+ "
\n",
+ " תרגול:\n",
+ " את הלולאה הזו כתב מתכנת מפוזר במיוחד, ויש בה יותר מבעיה אחת.
\n",
+ " מצאו את הבעיות, תקנו אותן והריצו את התוכנית.
\n",
+ " הפלט הרצוי הוא, משמאל לימין: 8, 4, 2, 1.\n",
+ "
סטייה ב־1
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " זו טעות כל־כך נפוצה שיש לה שם ואפילו ערך בוויקיפדיה!
\n",
+ " בשגיאה מסוג \"סטייה ב־1\" (באנגלית: \"Off By One\") מתכנת שוכח לטפל במקרה האחרון, או מטפל במקרה אחד יותר מדי.\n",
+ "
\n", + " נראה דוגמה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "numbers = [1, 2, 3, 4]\n", + "index = 0\n", + "total = 0\n", + "\n", + "while index <= len(numbers):\n", + " total = total + numbers[index]\n", + " index = index + 1\n", + "\n", + "print(total)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " תרגול:\n", + " מה הבעיה פה? איך ניתן לפתור אותה?\n", + "
\n", + "טיפול בבאגים של לולאות
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "לולאות הן כלי חזק שמוסיף עניין רב לקוד.
\n",
+ "יחד עם זאת, לולאות מוסיפות מקרים מיוחדים שגורמים לבאגים שקשה לפענח בהתחלה.
\n",
+ "הדרך הכי טובה למצוא בעיות, היא להדפיס את הערכים שנמצאים בלולאה ובאתחול המשתנים שלפניה, ולבדוק מה מצבם.\n",
+ "
מונחים
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True
, גוף הלולאה ירוץ.תרגולים
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "###It's the final...
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "נתקעתם במסיבה שבה סופרים את השניות לאחור עד השנה החדשה.
\n",
+ "עזרו למשתתפים המבולבלים שהתחילו לספור הרבה יותר מדי לפני הזמן –
\n",
+ "קבלו את מספר השניות שנותרו עד חצות, והדפיסו עבורם את הספירה לאחור.
\n",
+ "בסוף הספירה, הדפיסו \"Happy new year!\"\n",
+ "
\n",
+ "לדוגמה, עבור 4, הדפיסו:
\n",
+ " \n",
+ " 4\n",
+ " 3\n",
+ " 2\n",
+ " 1\n",
+ " Happy new year!\n",
+ " \n",
+ "
Play
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "ציירו פירמידה הפוכה, כך שראשה יהיה בצד ימין.
\n",
+ "במהלך הקוד, קבלו מהמשתמש את אורך השורה שבה מצויר קודקוד הפירמידה.
\n",
+ "לדוגמה: בפירמידה שלפניכם, המשתמש הכניס 5 כאורך השורה שבה מצויר קודקוד הפירמידה.\n",
+ "
מפענח הצפנים 2
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "הצופן לכספת הביתית שלכם הוא 4812. בנו משחק בול־פגיעה שמאפשר למשתמש לנסות לנחש את הצופן.
\n",
+ "למשתמש יש 3 ניסיונות לנחש נכונה את המספר שלכם לפני שמתחילה אזעקה.
\n",
+ "כחלק ממנגנון ההגנה מאיבוד הסיסמה של הכספת, היא מציגה כמה ספרות נכונות המשתמש הזין אחרי כל ניחוש.
\n",
+ "אפשרו למשתמש להזין קוד 3 פעמים, וכתבו לו בכל ניסיון כמה מתוך הספרות שהזין באמת קיימות בקוד הנכון, לאו־דווקא בסדר שהקיש.
\n",
+ "אם לא הצליח אחרי 3 ניסיונות, הדפיסו שהאזעקה הופעלה וסיימו את התוכנית.
\n",
+ "
\n",
+ "לדוגמה, אם המשתמש הקיש בניסיון הראשון 0634, הדפיסו לו שרק אחת הספרות שניחש נכונה.
\n",
+ "אם המשתמש הקיש בסיבוב השני 1234, הדפיסו לו ש־3 ספרות תואמות את הקוד המקורי.
\n",
+ "אם המשתמש הקיש בסיבוב השלישי 1284, הדפיסו לו ש־4 ספרות תואמות את הקוד המקורי, ואז הדפיסו לו שהופעלה האזעקה.
\n",
+ "אם המשתמש הקיש באחד הסיבובים 4812, הדפיסו שהכספת נפתחה בהצלחה וסיימו את התוכנית מיד.\n",
+ "
\n", + "השתמשו בלולאות.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "###כמו קולץ בישבן
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "נגדיר כלל: אם מספר הוא זוגי, נחלק אותו ב־2. אם המספר אי־זוגי, נכפיל אותו ב־3 ונוסיף לו 1.
\n",
+ "השערת קולץ טוענת שאם ניקח מספר חיובי שלם ונשתמש עליו פעמים רבות בכלל הזה, תמיד נסיים במספר 1.
\n",
+ "לדוגמה, אם ניקח את 52, נקבל את שרשרת הפעולות הבאה:\n",
+ "
\n",
+ "כתבו פונקציה שמקבלת מספר, ומחזירה את מספר הפעולות שצריך לעשות עליו לפי השערת קולץ כדי להגיע ל־1.
\n",
+ "לדוגמה: עבור המספר 52 היינו צריכים לבצע 11 פעולות כדי להגיע ל־1, ולכן הפונקציה תחזיר 1.\n",
+ "
ממש קולץ בישבן
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " מצאו עבור איזה מספר בין 1 ל־1,000, צריך לעשות את הכי הרבה צעדים לפי השערת קולץ כדי להגיע ל־1.
\n",
+ "לדוגמה, הנה הצעדים שצריך לעשות עבור כל מספר עד 5:\n",
+ "
\n", + "מכאן שהמספר בין 1 ל־5 שעליו יש לעשות הכי הרבה צעדים לפי השערת קולץ עד שמגיעים לאחד, הוא 3.\n", + "
" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/week3/2_Slicing.ipynb b/week3/2_Slicing.ipynb new file mode 100644 index 0000000..ca6781c --- /dev/null +++ b/week3/2_Slicing.ipynb @@ -0,0 +1,1053 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "חיתוך / Slicing
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##הקדמה
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " בשבוע שעבר למדנו כיצד ניגשים לרשימה או למחרוזת במיקום מסוים:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "great_quote = \"Accept who you are. Unless you're a serial killer.\"\n", + "print(\"The 1st character is: \" + great_quote[0])\n", + "print(\"The 6th character is: \" + great_quote[5])\n", + "print(\"The last character is: \" + great_quote[-1])\n", + "great_quote_by_words = great_quote.split()\n", + "print(\"great_quote_by_words = \" + str(great_quote_by_words))\n", + "print(\"The 1st word is: \" + great_quote_by_words[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " זוהי יכולת שימושית מאוד, אך לעיתים ישנו צורך לקחת חלק מהאיברים של המשתנה שהגדרנו, ולבנות מהם רשימה או מחרוזת חדשה.
\n",
+ " לדוגמה במקרה הבא, שבו התגנב למחרוזת שלנו מספר מיותר שהיינו שמחים להעלים משם:\n",
+ "
\n",
+ " תרגול:\n",
+ " ממשו דרך לקבל את המחרוזת ללא המספר.
\n",
+ " חשבו על דרך אחת נוספת.\n",
+ "
הגדרה
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "חיתוך (או Slicing) היא שיטה שמטרתה לקבל כמה איברים מתוך ערך מסוים.
\n",
+ "במחרוזת, חיתוך יעזור לנו לקבל תת־מחרוזת מתוך המחרוזת השלמה.
\n",
+ "ברשימה, חיתוך יעזור לנו לקבל תת־רשימה מתוך המחרוזת השלמה.
\n",
+ "
חיתוך בפייתון
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "###חיתוך לפי טווח
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "נבחן את המחרוזת הבאה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "word = 'Avoc42ado'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "מטרתנו תהיה להשיג את החלק הראשון של המחרוזת, זה שנמצא לפני ה־42, באמצעות חיתוך.
\n",
+ "לשם כך, נביט על המיקומים של כל אות:\n",
+ "
0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "4 | \n", + "5 | \n", + "6 | \n", + "7 | \n", + "8 | \n", + "
\"A\" | \n", + "\"v\" | \n", + "\"o\" | \n", + "\"c\" | \n", + "\"4\" | \n", + "\"2\" | \n", + "\"a\" | \n", + "\"d\" | \n", + "\"o\" | \n", + "
-9 | \n", + "-8 | \n", + "-7 | \n", + "-6 | \n", + "-5 | \n", + "-4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "
\n",
+ "לפי השרטוט, אנחנו רוצים לחתוך ממיקום 0 ועד מיקום 3.
\n",
+ "נבקש מפייתון את המיקומים בצורה הבאה:
\n",
+ "
0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "4 | \n", + "5 | \n", + "6 | \n", + "7 | \n", + "8 | \n", + "
\"A\" | \n", + "\"v\" | \n", + "\"o\" | \n", + "\"c\" | \n", + "\"4\" | \n", + "\"2\" | \n", + "\"a\" | \n", + "\"d\" | \n", + "\"o\" | \n", + "
-9 | \n", + "-8 | \n", + "-7 | \n", + "-6 | \n", + "-5 | \n", + "-4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "
\n",
+ " קל לזכור שפייתון לא לוקח את האיבר האחרון:
\n",
+ " אם ניקח את המיקום של האיבר האחרון, ונחסר ממנו את המיקום של האיבר הראשון – נקבל את מספר האיברים שחזרו.
\n",
+ " במקרה שלנו – 4 פחות 0 יוצא 4, שזה בדיוק מספר האיברים שקיבלנו בחזרה.\n",
+ "
\n",
+ " אנשים רבים נוטים להתבלבל בין חיתוך לבין לקריאה לפונקציה.
\n",
+ " טעות זו גורמת לשימוש בסוגריים עגולים במקום מרובעים, או בפסיק במקום נקודותיים.\n",
+ "
\n", + " חיתוכים לא משנים את המחרוזת המקורית, אלא אם נבצע השמה.\n", + "
\n", + "\n", + "אם אנחנו מעוניינים להתחיל את החיתוך מההתחלה, נוכל להשמיט את החלק שלפני הנקודותיים:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# We can use slicing with implicit starting index\n", + "word[:4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "נשתמש בטריק דומה כדי לחלץ את החלק השני של המחרוזת – מתא 6 ועד סוף המחרוזת:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "word[6:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "4 | \n", + "5 | \n", + "6 | \n", + "7 | \n", + "8 | \n", + "\n", + " |
\"A\" | \n", + "\"v\" | \n", + "\"o\" | \n", + "\"c\" | \n", + "\"4\" | \n", + "\"2\" | \n", + "\"a\" | \n", + "\"d\" | \n", + "\"o\" | \n", + "\n", + " |
-9 | \n", + "-8 | \n", + "-7 | \n", + "-6 | \n", + "-5 | \n", + "-4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "\n", + " |
\n", + "אחרי שחתכנו כל־כך יפה את המחרוזת של האבוקדו, הגיע הזמן להינות מהפירות:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "word[:4] + word[6:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " תרגול:\n", + " כתבו שורה שמשיגה רק את תת המחרוזת \"42\" מתוך המחרוזת.\n", + "
\n", + "חיתוך בקפיצות
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "אגף כוח האדם הנהדר של צה\"ל ביקש מכם להשיג את האותיות A, c, a מתוך המחרוזת שהוצגה למעלה.
\n",
+ "אם נבדוק היטב, נגלה שהאותיות מופיעות החל מהתא ה־0, בקפיצות של 3 כל פעם.
\n",
+ "למזלנו, בפייתון יש דרך פשוטה להפליא לחתוך תוך כדי קפיצות בין אות לאות – להוסיף נקודותיים, ואז את גודל הקפיצה!\n",
+ "
\n",
+ "למה זה לא הצליח?
\n",
+ "נזכר שפייתון לא אוהב לקחת את המקום האחרון:\n",
+ "
0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "4 | \n", + "5 | \n", + "6 | \n", + "7 | \n", + "8 | \n", + "
\"A\" | \n", + "\"v\" | \n", + "\"o\" | \n", + "\"c\" | \n", + "\"4\" | \n", + "\"2\" | \n", + "\"a\" | \n", + "\"d\" | \n", + "\"o\" | \n", + "
-9 | \n", + "-8 | \n", + "-7 | \n", + "-6 | \n", + "-5 | \n", + "-4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "
\n", + " נתקן, ועל הדרך ניזכר שלא באמת צריך את ה־0 שם בהתחלה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "word[:7:3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "4 | \n", + "5 | \n", + "6 | \n", + "7 | \n", + "8 | \n", + "
\"A\" | \n", + "\"v\" | \n", + "\"o\" | \n", + "\"c\" | \n", + "\"4\" | \n", + "\"2\" | \n", + "\"a\" | \n", + "\"d\" | \n", + "\"o\" | \n", + "
-9 | \n", + "-8 | \n", + "-7 | \n", + "-6 | \n", + "-5 | \n", + "-4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "
חיתוך הפוך
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " כחובבים גדולים של שירה לירית, הפעם המטרה שלנו תהיה להשיג את המחרוזת \"oda\".
\n",
+ "
\n",
+ " נשים לב שמדובר בתאים 6, 7 ו־8 בסדר הפוך.
\n",
+ " נוכל לנסות להפוך את הסדר של הפרמטרים:
\n",
+ "
\n",
+ " אך מהר מאוד נגלה שישנה בעיה בהתקדמות נגד כיוון החץ –
\n",
+ " אי אפשר להגיע מתא 8 לתא 5 אם אנחנו מתקדמים ימינה.\n",
+ "
0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "4 | \n", + "5 | \n", + "6 | \n", + "7 | \n", + "8 | \n", + "\n", + " |
\"A\" | \n", + "\"v\" | \n", + "\"o\" | \n", + "\"c\" | \n", + "\"4\" | \n", + "\"2\" | \n", + "\"a\" | \n", + "\"d\" | \n", + "\"o\" | \n", + "\n", + " |
-9 | \n", + "-8 | \n", + "-7 | \n", + "-6 | \n", + "-5 | \n", + "-4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "\n", + " |
\n",
+ " כל מה שנצטרך זה לבקש לקפוץ בצעדים של -1.
\n",
+ " כשכמות הצעדים (הקפיצות) שלנו תכיל מספר שלילי, כיוון החץ תמיד יהיה מימין לשמאל:\n",
+ "
0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "4 | \n", + "5 | \n", + "6 | \n", + "7 | \n", + "8 | \n", + "
\"A\" | \n", + "\"v\" | \n", + "\"o\" | \n", + "\"c\" | \n", + "\"4\" | \n", + "\"2\" | \n", + "\"a\" | \n", + "\"d\" | \n", + "\"o\" | \n", + "
-9 | \n", + "-8 | \n", + "-7 | \n", + "-6 | \n", + "-5 | \n", + "-4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "
\n", + " ובמקרה כזה, סוף המחרוזת שאנחנו חותכים נחשבת התחלת המחרוזת (כי החיתוך מתחיל מימין):\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "word[:5:-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " תרגול:\n",
+ " חיתכו מהמחרוזת את תת־המחרוזת \"covA\".
\n",
+ " בשורה נפרדת, מצאו דרך לקבל את תת־המחרוזת \"oda24covA\" בעזרת חיתוך.\n",
+ "
דוגמאות נוספות
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " חיתוך עובד בצורה זהה על רשימה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# 0 1 2 3 4 5\n", + "animals = ['duck', 'pig', 'cow', 'cat', 'dog', 'shark']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals[2:4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals[1:4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals[5:1:-2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals[:1:-2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals[5::-2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals[::-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "אפשר לעבוד גם עם מיקומים שליליים.
\n",
+ "עבור פייתון זה אותו דבר:\n",
+ "
תרגולים
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "###איזה עולם
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hello = \"Hello World\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "שרשרו את המחרוזות הבאות יחד, לפי הסדר שהן מוצגות בתרגיל.
\n",
+ "לצורך התרגיל, התייחסו ל־H כתו הראשון במחרוזת. כמו כן, התייחסו לרווח כתו לכל דבר.\n",
+ "
מסר סודי ביותר
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "ארפכשד העביר לכדרלעומר מסר סודי ומוצפן.
\n",
+ "במחזורת הבאה, אם תקפצו כל פעם מספר מסוים של אותיות, תקבלו מסר חשוב הכולל את סיסמתו של ארפכשד.
\n",
+ "מצאו את מספר האותיות שצריך לדלג כל פעם כדי להשיג את המסר הסודי שנשלח לארפכשד.\n",
+ "
\n",
+ "רמז: במחרוזת יש את המילה password
.\n",
+ "
\n",
+ "לפניכם דוגמה של קובץ טקסט שמסודר בצורה שמזכירה טבלה.
\n",
+ "הקובץ מכיל את עשרים הפוקימונים הראשונים. העמודות מופרדות אחת מהשנייה בפסיקים.
\n",
+ "החזירו רשימה של רשימות, כאשר כל רשימה מייצגת שורה בטבלה, וכל תא ברשימה הזו מייצג את הערך שנמצא בעמודה באותה רשימה.
\n",
+ "מחקו מהרשימות את עמדות Generation (הרי שכולם מדור ראשון), ואת עמודת Legendary (אף אחד מהם אינו אגדי).
\n",
+ "מחקו גם את עמודת Total.\n",
+ "
\n", + " דוגמה לפלט שאמור לצאת לכם עבור 3 השורות הראשונות:\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "[\n", + " ['#', 'Name', 'Type 1', 'Type 2', 'HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed'],\n", + " ['1', 'Bulbasaur', 'Grass', 'Poison', '45', '49', '49', '65', '65', '45'],\n", + " ['2', 'Ivysaur', 'Grass', 'Poison', '60', '62', '63', '80', '80', '60'],\n", + "]\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "בונוס: המירו את המקומות ברשימה שמכילים מספרים לטיפוסים מסוג int.
\n",
+ "זהו לא תרגיל פשוט. הרגישו בנוח לפתוח מחברות משבוע קודם ולהעזר במדריכים.\n",
+ "
\n",
+ " קובץ הוא מבנה שמאגד בתוכו נתונים השמורים במחשב שלכם.
\n",
+ " לקובץ יש שם וכתובת (נתיב, או באנגלית path), והוא מכיל כמות מסוימת של מידע שמשפיעה על גודלו.
\n",
+ " התוכן של כל קובץ מגדיר את הסוג שלו. סוגי קבצים שונים משמשים למטרות שונות, לדוגמה:\n",
+ "
סוג הקובץ | \n", + "מטרת הקובץ | \n", + "דוגמאות לסיומות | \n", + "
---|---|---|
טקסט | \n", + "מכיל מלל בלבד, ללא עיצוב כלשהו (הדגשות, גדלים וכדומה) | \n", + "txt | \n", + "
תמונה | \n", + "ייצוג של תמונה דיגיטלית למטרת הצגה חזותית שלה | \n", + "png, jpg, gif, bmp | \n", + "
וידאו | \n", + "ייצוג של סרט או כל תצלום חוזי (וידאו) אחר | \n", + "mp4, avi, flv | \n", + "
פייתון | \n", + "מכיל קוד שהתוכנה של פייתון יודעת לקרוא ולהפעיל | \n", + "py, pyc, pyd | \n", + "
הרצה | \n", + "מכיל סדרת הוראות המיועדות לקריאה ולהרצה על־ידי המחשב | \n", + "exe, dmg | \n", + "
\n",
+ "קבצים הם דרך נהדרת לקבל מבט חטוף לעומק ולמורכבות של המכונה המדהימה שנקראת מחשב.
\n",
+ "ננסה לצייר לכם תמונה מלאה – נתחיל מהשכבה הנמוכה ביותר, הכונן הקשיח שלכם, ולבסוף נגיע לקבצים.\n",
+ "
\n",
+ "כונן קשיח הוא אחד מהרכיבים הנמצאים בקופסת המחשב שעליו אתם עובדים כרגע.
\n",
+ "זהו הרכיב שמאחסן לטווח ארוך את המידע במחשב שלכם – קבצים, תוכנות, מערכת ההפעלה והגדרות כמו העדפות השפה שלכם.
\n",
+ "היתרון המובהק של כוננים קשיחים הוא שהם יודעים לשמור על המידע שלכם לאורך זמן, גם אם הם לא מוזנים בחשמל באותו רגע.\n",
+ "
\n",
+ "כוננים קשיחים מכילים הרבה יחידות קטנטנות בשם \"ביט\".
\n",
+ "ביט הוא ערך שיכול להיות 0 (אין זרם חשמלי) או 1 (יש זרם חשמלי).
\n",
+ "בכל כונן קשיח פשוט שנמכר היום יש מקום למאות מיליארדי(!) ביטים כאלו.
\n",
+ "כך נשמר כל המידע שדיברנו עליו בפסקה הקודמת.\n",
+ "
\n",
+ "אם נסתכל בעיניים אנושיות על רצפי התאים הקטנטנים, הביטים, שנמצאים בכונן הקשיח, כנראה שלא נבין מהם כלום.
\n",
+ "הנה דוגמה לרצף שכזה: 0100100001100101011011000110110001101111001000000101011101101111011100100110110001100100.
\n",
+ "איך יוצקים משמעות לתוך דבר כזה? מה רצף המספרים הזה אומר בכלל?\n",
+ "
\n",
+ "נדמיין לרגע שאנחנו הממציאים של המחשב, והמטרה שלנו היא לייצג טקסט בצורה שיהיה קל לשמור אותו ולקרוא אותו לאחר־מכן.
\n",
+ "תוכלו לחשוב על דרך לעשות זאת רק באמצעות רצפים של 0 ו־1?\n",
+ "
\n",
+ "בעיה דומה, של ייצוג טקסט באמצעות אפסים ואחדים בלבד, עלתה אי שם ב־1960.
\n",
+ "אני אחסוך לכם הרבה מעשיות בדרך, אבל מפה לשם הוחלט על תקן בשם ASCII, שקובע שכל סידור של 8 ביטים שכאלו (\"בייט\") ייצגו תו.
\n",
+ "אז האות A קיבלה את הייצוג 01000001, האות Z, למשל, קיבלה את הייצוג 01011010, הספרה 7 את הייצוג 00110111 והתו רווח את הייצוג 00100000.
\n",
+ "כך אפשר לקרוא מסר ארוך מאוד, ולהמיר כל 8 ביטים רצופים לאות. אם ננסה לקרוא בשיטה הזו 80 ביטים, נקבל 10 תווים.\n",
+ "
\n",
+ "אבל רגע! מה קורה אם אני רוצה לייצג תמונה של חתול? או סירטון של חתול? או סאונד של... ובכן, חתול?
\n",
+ "כמו שאנשים חכמים חשבו על דרך לייצג ASCII, חכמים אחרים חשבו, עבור כל סוג של קובץ – מתמונה ועד תוכנה שרצה על המחשב, על איך מייצגים אותם באמצעות ביטים.
\n",
+ "גם בימים אלו, אנשים מוכשרים רבים יושבים וחושבים על דרכים טובות יותר לייצג מידע בעזרת ביטים, ויוצרים עבורינו סוגי קבצים חדשים.
\n",
+ "
\n",
+ "כשאנחנו רוצים לפתוח תמונה של חתול, למשל, אנחנו מפעילים תוכנה ייעודית שיודעת לקרוא ייצוג של תמונות.
\n",
+ "מה שקורה באותו רגע מאחורי הקלעים הוא שהתוכנה קוראת רצפים של 0 ו־1 מהדיסק הקשיח, אותם ביטים שדיברנו עליהם.
\n",
+ "מי שצילם את התמונה השתמש בתוכנה שיודעת להמיר את מה שקרה על מסך המצלמה לביטים שנשמרו על כרטיס הזכרון שלו.
\n",
+ "מי שתכנת את התוכנה שמציגה לנו כרגע את החתול ידע להגיד לה כיצד לתרגם את אותם ביטים לתמונה שמוצגת לכם על המסך.
\n",
+ "שניהם פעלו לפי תקן מסוים (יש כמה כאלו, אולי אתם מכירים: JPG, PNG, GIF ועוד), שאומר איך מייצגים תמונה בעזרת ביטים.
\n",
+ "בסופו של דבר, עבור התוכנה החתול שלכם הוא בסך־הכל משבצות קטנטנות בצבעים שונים שמצוירות זו על־יד זו.\n",
+ "
\n", + " כשמתפתח ייצוג מסוים של קובץ, הוא נקרא \"פורמט\", או בעברית \"תַּסְדִיר\".\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### קבצים טקסטואלים וקבצים בינאריים" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "חלק מהקבצים, כמו מסמכי טקסט או תוכניות פייתון, יכולים להיות קבצים טקסטואליים.
\n",
+ "ישנם סוגי קבצים טקטואליים נוספים, כמו CSV שמייצג מידע טבלאי באמצעות טקסט, או HTML שמייצג קוד שבעזרתו המחשב יודע להציג דף אינטרנט.
\n",
+ "המשותף לקבצים אלו שאם ממירים את הבייטים שמהם הם מורכבים לתווים, מקבלים תוצאה שנוח לבני־אדם לקרוא, ולא רק למחשב.\n",
+ "
\n",
+ "ישנם גם סוגי קבצים אחרים שלא נועדו לקריאה על־ידי עין אנושית.
\n",
+ "קבצים כאלו נקראים \"קבצים בינאריים\", ונלמד לטפל בחלק מהם בשלב מתקדם יותר בקורס.
\n",
+ "
\n", + " ניתן דוגמה לכמה סוגי קבצים בינאריים:\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " במהלך החוברת הזו, אנו נלמד לטפל בקבצים טקסטואליים.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## טיפול בקבצים" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " אם בעבר היינו משתמשים בפנקס כדי לשמור דברים, הרי שהיום שימוש בקבצים ממוחשבים הופך את הכל לקל ומהיר.
\n",
+ " מעבר לזה – על קבצים ממוחשבים אפשר לבצע חישובים מסובכים תוך חלקיק שנייה, מה שנותן לנו יכולות מופתיות שלא היו לנו בעבר.\n",
+ "
\n",
+ " קבצים הם מקור מצויין לקלט ולפלט עבור התוכניות שאנחנו בונים.
\n",
+ " כמקור קלט, הם יכולים לכלול בקלות שורות רבות או מידע מורכב.
\n",
+ " כפלט, הם מאפשרים לנו לשמור מידע בין הרצה להרצה, להעביר את המידע ממקום למקום בקלות ולייצג את המידע שלנו בצורה מורכבת.\n",
+ "
\n",
+ "בקובץ passwords.txt שנמצא בתוך תיקיית resources, אספנו לכם את 25 הסיסמאות הנפוצות ביותר בעולם.
\n",
+ "בתור התחלה, בואו ננסה להציץ במה כתוב בתוך הקובץ בעזרת פייתון. \n",
+ "
\n",
+ "הפונקציה open
יודעת לפתוח קובץ ולהחזיר לנו ערך שמצביע עליו, מה שיאפשר לנו לכתוב קוד שעושה בקובץ שימוש.
\n",
+ "הערך הזה שמצביע על הקובץ נקרא File handler, סוג חדש של ערך שעליו נוכל לבצע שלל פעולות.
\n",
+ "הפונקציה open
מקבלת 2 פרמטרים: הראשון הוא הנתיב לקובץ, והשני הוא צורת הגישה לקובץ.
\n",
+ "
\n",
+ " הפרמטר השני, צורת הגישה לקובץ, הוא מחרוזת.
\n",
+ " טעות נפוצה היא לשים שם r, w או a בלי גרשיים מסביב.\n",
+ "
\n", + "נתחיל בפתיחת הקובץ, והשמה של ה־file handler למשתנה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "common_passwords_file = open('resources/passwords.txt', 'r')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "כך נראה הסוג של file handler המצביע לקובץ טקסטואלי:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "type(common_passwords_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### קריאת קובץ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "עכשיו, כשהקובץ פתוח, נוכל להשתמש בו.
\n",
+ "נבקש מפייתון לקרוא את תוכן הקובץ באמצעות הפעולה read
, ונשמור את התוכן שחוזר מהפעולה על משתנה:\n",
+ "
\n", + "נשים לב שמה שחזר לנו מפעולת הקריאה הוא מחרוזת לכל דבר:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "type(common_passwords)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "זיכרו ששורות חדשות מיוצגות על־ידי התו \\n, וכך גם ב־common_passwords:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "common_passwords" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " תרגול:\n",
+ " פתחו וקראו את הקובץ בעצמכם, קבלו מהמשתמש את הסיסמה שלו, והדפיסו האם היא בין 25 הסיסמאות הנפוצות ביותר.
\n",
+ " בונוס: אם היא בין 25 הסיסמאות הנפוצות, החזירו את המיקום שלה ברשימה.\n",
+ "
\n", + "אם ננסה לקרוא שוב את הקובץ, נגלה תופעה מעט מוזרה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "common_passwords_again = common_passwords_file.read()\n", + "print(common_passwords_again)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ???\n", + "common_passwords_again == ''" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "קריאה נוספת של הקובץ החזירה לנו הפעם שהוא ריק!
\n",
+ "אתם ודאי תשמחו לגלות שזו התנהגות צפויה – וזה הכל באשמתו של הסמן.\n",
+ "
\n",
+ "כאשר אנחנו פותחים קובץ לקריאה, הסמן (באנגלית: cursor) מצביע לתחילת הקובץ.
\n",
+ "ודאי תופתעו לדעת שאתם כבר מכירים את הרעיון של סמן!
\n",
+ "דמיינו שאתם פותחים מסמך לעריכה, או אפילו פותרים תרגיל במחברת, ותיזכרו בקו המהבהב שמראה לכם את המיקום שאליו האות שתכתבו תתווסף.
\n",
+ "ברגע שאתם מבקשים מפייתון לקרוא את הקובץ בעזרת read
, היא קוראת מהמקום בו נמצא הסמן ועד סוף הקובץ.
\n",
+ "בזמן הקריאה, פייתון תעביר את הסמן לסוף הקובץ, ולכן כשתנסו לקרוא אותו שוב – תקבלו מחרוזת ריקה.\n",
+ "
\n",
+ "כדי להחזיר את הסמן לתחילת הקובץ, נשתמש בפעולה seek
ונבקש ממנה להחזיר את הסמן כך שיצביע למקום 0 – לפני התו הראשון:\n",
+ "
\n",
+ "ניתן לראות איפה הסמן נמצא באמצעות הפעולה tell
:\n",
+ "
\n",
+ "מכאן ניתן להסיק, שאם נעשה seek
ונספק כארגומנט 224, נעביר את הסמן כך שיצביע לסוף הקובץ. \n",
+ "
\n",
+ "לעיתים, במיוחד כשיש קובץ גדול במיוחד, נעדיף לקרוא כל פעם רק חלק מהקובץ.
\n",
+ "נוכל לבחור לקרוא מספר מסוים של תווים באמצעות הפעולה read
שאנחנו כבר מכירים,
\n",
+ "אלא שהפעם נעביר לה ארגומנט שיגיד לה כמה תווים לקרוא:\n",
+ "
\n", + "כדאי לזכור שהסמן יהיה עכשיו במקום 10, והפעלה נוספת של פעולת הקריאה תמשיך מהמקום הזה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "common_passwords_file.read(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "פייתון מאפשר לנו לקרוא גם עד סוף השורה הנוכחית, שעליה נמצא הסמן, באמצעות הפעולה readline
.
\n",
+ "שימו לב שהשורה תסתיים בתווים המייצגים שורה חדשה:\n",
+ "
\n",
+ "לקריאת כל השורות בקובץ, ניתן להשתמש בפעולה readlines
, שתחזיר לנו רשימת מחרוזות.
\n",
+ "כל מחרוזת ברשימה מייצגת שורה אחת בקובץ:\n",
+ "
\n",
+ " תרגול:\n",
+ " כתבו פונקציה שמקבלת נתיב לקובץ, ומחזירה רשימה בה כל איבר הוא שורה בקובץ.
\n",
+ " בניגוד לפעולה readlines
, המחרוזות ברשימה לא יסתיימו בתו שמייצג ירידת שורה.\n",
+ "
\n",
+ "כמו שלהשאיר דלת פתוחה נחשב מנהג גס־רוח, במחשבים אנחנו נוהגים לסגור קבצים לאחר שסיימנו להשתמש בהם.
\n",
+ "קובץ פתוח תופס משאבי מערכת (כמו זכרון), ולעיתים יגרום לכך שתוכנות אחרות לא יוכלו לגשת אליו.
\n",
+ "השארת קבצים פתוחים הוא מנהג מגונה שיגרום להאטה בביצועים, ואפילו לקריסות בלתי צפויות במידה ויש יותר מדי file handlers פתוחים.\n",
+ "
\n",
+ "לא מדובר בפעולה מסובכת מדי. כל מה שתצטרכו לעשות הוא להשתמש בפעולה close
:\n",
+ "
\n", + "שימו לב שניסיון לעשות כל שימוש בקובץ אחרי סגירתו, יכשל:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "common_passwords_file.read()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### כתיבה לקובץ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "נסתכל שוב על המידע שראינו בתרגיל על הפוקימונים:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pokemons = \"\"\"\n", + "#,Name,Type 1,Type 2,Total,HP,Attack,Defense,Sp. Atk,Sp. Def,Speed,Generation,Legendary\n", + "1,Bulbasaur,Grass,Poison,318,45,49,49,65,65,45,1,False\n", + "2,Ivysaur,Grass,Poison,405,60,62,63,80,80,60,1,False\n", + "3,Venusaur,Grass,Poison,525,80,82,83,100,100,80,1,False\n", + "4,Charmander,Fire,,309,39,52,43,60,50,65,1,False\n", + "5,Charmeleon,Fire,,405,58,64,58,80,65,80,1,False\n", + "6,Charizard,Fire,Flying,534,78,84,78,109,85,100,1,False\n", + "7,Squirtle,Water,,314,44,48,65,50,64,43,1,False\n", + "8,Wartortle,Water,,405,59,63,80,65,80,58,1,False\n", + "9,Blastoise,Water,,530,79,83,100,85,105,78,1,False\n", + "10,Caterpie,Bug,,195,45,30,35,20,20,45,1,False\n", + "11,Metapod,Bug,,205,50,20,55,25,25,30,1,False\n", + "12,Butterfree,Bug,Flying,395,60,45,50,90,80,70,1,False\n", + "13,Weedle,Bug,Poison,195,40,35,30,20,20,50,1,False\n", + "14,Kakuna,Bug,Poison,205,45,25,50,25,25,35,1,False\n", + "15,Beedrill,Bug,Poison,395,65,90,40,45,80,75,1,False\n", + "16,Pidgey,Normal,Flying,251,40,45,40,35,35,56,1,False\n", + "17,Pidgeotto,Normal,Flying,349,63,60,55,50,50,71,1,False\n", + "18,Pidgeot,Normal,Flying,479,83,80,75,70,70,101,1,False\n", + "19,Rattata,Normal,,253,30,56,35,25,35,72,1,False\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "הפעם, נכתוב אותו לתוך קובץ מתסדיר CSV.
\n",
+ "כדי לכתוב לקובץ נשתמש בפעולה write
, לאחר שנפתח את הקובץ במצב כתיבה (w).\n",
+ "
\n", + " זהירות! פתיחת קובץ קיים במצב w תמחק את התוכן שלו מיידית.\n", + "
\n", + "\n",
+ " במידה ופתחנו קובץ לכתיבה והקובץ לא קיים במערכת שלנו, פייתון יבדוק האם התיקייה שמעליו קיימת.
\n",
+ " אם כן – פייתון יצור את הקובץ בשבילנו.\n",
+ "
\n", + "המספר שפייתון מחזיר הוא כמות התווים שייכתבו לקובץ.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "אם תחפשו את הקובץ במחשב ותפתחו אותו, אתם תגלו שפייתון עדיין לא כתב אליו את הנתונים.
\n",
+ "פייתון שומר את הנתונים שביקשתם לכתוב בצד במעין מנגנון זיכרון זמני שנקרא buffer, ויכתוב אותם לקובץ כשתסגרו אותו.
\n",
+ "תוכלו להכריח את פייתון לכתוב לקובץ עוד לפני שסגרתם אותו באמצעות הפעולה flush
:\n",
+ "
\n", + "לסיום, לא נשכח לסגור את הקובץ כשאנחנו יודעים שכבר לא נשתמש בו:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pokemons_file.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " כשאתם בתוך המחברת, ניתן להשתמש בסימן קריאה כדי להריץ דברים שלא קשורים לפייתון.
\n",
+ " לדוגמה: !pokemon.csv
יריץ את הקובץ שכתבנו.
\n",
+ " שימו לב שלא תוכלו להריץ שום דבר אחר במחברת עד שתסגרו את הקובץ.\n",
+ "
\n",
+ "ניתן לפתוח קובץ במצב 'w' אם נרצה לכתוב לקובץ חדש, או לדרוס קובץ קיים.
\n",
+ "אם נרצה להוסיף שורות לקובץ קיים, נפתח את הקובץ במצב ההוספה 'a' שמסמן append.\n",
+ "
\n", + "נוסיף את פוקימון מספר 20, רטיקייט, לקובץ הפוקימונים:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "new_line = \"\\n20,Raticate,Normal,,413,55,81,60,50,70,97,1,False\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pokemons_table = open('pokemon.csv', 'a')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "הוספת התוכן לקובץ במצב הוספה תתבצע באמצעות הפעולה write
, בדיוק כמו בכתיבת קובץ חדש:\n",
+ "
\n",
+ "מילת המפתח with
מאפשרת לנו לאגד כמה שורות תחת אותו הקשר.
\n",
+ "במקרה של קבצים, היא מאפשרת לנו לאגד תחתיה שורות שמטרתן טיפול בקובץ מסוים.
\n",
+ "לדוגמה, השורות הבאות:\n",
+ "
\n",
+ " יכולות להכתב אחרת בעזרת מילת המפתח with
:\n",
+ "
\n",
+ " שימו לב לצורת השימוש ב־with
:\n",
+ "
with
.as
.\n",
+ " בתור מתכנתים, זו בחירה שלכם איך לכתוב את הקוד שלכם.
\n",
+ " ובכל זאת, קל לראות את היתרונות של שימוש ב־with
:
\n",
+ " הקוד הופך להיות קריא ומסודר יותר, והקובץ נסגר לבד כשמסתיימת ההזחה.\n",
+ "
\n",
+ " כתיבת קוד עם with
היא יותר פשוטה ממה שהיא נראית בהתחלה –
\n",
+ " 5 הסעיפים הראשונים התייחסו לשורה הראשונה, ששקולה לשורה הראשונה והרביעית בקוד בלי ה־with
.\n",
+ "
\n",
+ " בקובץ cereal.csv שנמצא בתיקיית resources, ישנו מידע תזונתי על מִדְגַּנִּים שונים (יענו, דגני בוקר).
\n",
+ " ככל שהמדגנים שמופיעים בשורה מסויימת בריאים יותר, כך המספר שמופיע לידם תחת העמודה rating גבוה יותר.
\n",
+ " נמצאו את המדגנים הבריאים ביותר והדפיסו את שמם לצד הציון שקיבלו.
\n",
+ " קרדיט: את הקובץ הבאנו מכאן.\n",
+ "
\n",
+ "בקובץ hope.txt שנמצא בתיקיית resources, נמצאת אחת הפואמות המהממות של אמילי דיקנסון, תִּקְוָה הִיא בַּעֲלַת-הַנוֹצָה.
\n",
+ "אך אבוי! הפואמה התבלגנה, וכעת סדר המילים בכל שורה הוא הפוך.\n",
+ "
\n", + "במקום:\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " תִּקְוָה הִיא בַּעֲלַת-הַנוֹצָה" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " זוּ בַּנְּשָׁמָה תִשְׁכֹּן –\n", + "
\n", + "מופיע:\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " בַּעֲלַת-הַנוֹצָה הִיא תִּקְוָה" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " – תִשְׁכֹּן בַּנְּשָׁמָה זוּ\n", + "
\n",
+ "שמרו גיבוי של הקובץ בצד, וכתבו קוד שמסדר את הפואמה המבולגנת.
\n",
+ "שמרו את הפואמה המסודרת בקובץ חדש ששמו hope2.txt.\n",
+ "
\n",
+ " עד כה למדנו שישנם שני אופרטורים חשבוניים שעובדים על רשימות: חיבור וכפל.
\n",
+ " חיבור משרשר רשימה אחת לאחרת, וכפל משרשר רשימה לעצמה מספר פעמים.
\n",
+ " ניזכר בדוגמאות:\n",
+ "
\n", + " למדנו גם שאפשר להשוות בין רשימות בעזרת אופרטורי השוואה, עליהם למדנו בשיעור על ביטויים בוליאניים.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "numbers == [1, 2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "1 in numbers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "[1, 2] in numbers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " השבוע כבר הספקנו ללמוד על חיתוכים (Slicing), כך שאנחנו כבר מחזיקים בדי הרבה ידע לגבי איך מתפעלים רשימות.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(numbers)\n", + "print(\"Flip the order: \" + str(numbers[::-1]))\n", + "print(\"Only first 4 items: \" + str(numbers[:4]))\n", + "print(\"Only first 4 items, in reversed order:: \" + str(numbers[3::-1]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " למרות כל הידע המועיל שצברנו עד עכשיו, טרם נגענו בפעולות השייכות לנתונים מסוג רשימה.
\n",
+ " הפעולות האלו יתווספו לארגז הכלים שלנו, יקלו על כתיבת הקוד ויהפכו את הקוד שלנו לקריא יותר.\n",
+ "
\n", + "נגדיר רשימה שתשמש אותנו לדוגמאות:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals = ['pig', 'shark', 'lion']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "במהלך המעבר על הדוגמאות, נשים לב שפעולות על רשימה מתבצעות על הרשימה עצמה.
\n",
+ "זה אומר שלא נצטרך להשתמש בהשמה כדי לשנות את הרשימה שעליה אנחנו עובדים.\n",
+ "
\n",
+ "רשימה היא סוג נתונים נוח מאוד, בין היתר מכיוון שניתן להוסיף לה כמה איברים שנרצה.
\n",
+ "נוכל להוסיף איבר לסוף הרשימה באמצעות הפעולה append
:\n",
+ "
\n", + "הפעולה הזו תשיג תוצאה זהה לקוד שכתבנו עד היום בדרך טיפה פחות אלגנטית:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals = animals + ['duck']\n", + "print(animals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "שימו לב שבניגוד לשורה שמופיעה למעלה, append
מאפשרת להוסיף כל פעם איבר אחד בלבד.
\n",
+ "ניסיון להעביר לפעולה append
רשימה, נניח, יוסיף את הרשימה כולה כאיבר אחד ברשימה:\n",
+ "
\n", + " תרגול:\n", + " כתבו פונקציה שמקבלת מספר, ומחזירה רשימה של כל המספרים החיוביים הזוגיים עד אותו מספר.\n", + "
\n", + "\n",
+ "נוכל להסיר איבר מסוף הרשימה באמצעות קריאה פשוטה לפעולה pop
:\n",
+ "
\n", + "הפעולה הזו תשיג תוצאה זהה למה שעשינו השבוע בצורה המסורבלת הבאה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals = animals[:-1]\n", + "print(animals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "הפעולה pop
מחזירה את הערך שהוציאה, כך שאפשר לשמור אותו בצד:\n",
+ "
\n",
+ "הפעולה גם מאפשרת לנו לבחור את המקום שממנו אנחנו מעוניינים להוציא את הערך.
\n",
+ "נעשה זאת בעזרת העברת ארגומנט עם מיקום הערך שאנחנו רוצים להוציא מהרשימה:\n",
+ "
\n", + "כדי להסיר יותר מאיבר אחד, יתכן שעדיין תעדיפו להשתמש בחיתוך רשימות.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " תרגול:\n",
+ " כתבו פונקציה שמקבלת רשימה, ומחזירה רשימה עם סדר איברים הפוך.
\n",
+ " השתמשו בפעולה pop
.
\n",
+ " לדוגמה: אם תועבר לפונקציה הרשימה [3, 2, 1]
, הפונקציה תחזיר [1, 2, 3]
.\n",
+ "
\n",
+ "נוכל להוסיף יותר מאיבר אחד במכה בעזרת הפעולה extend
:\n",
+ "
\n", + "במבט ראשון, הפעולה תשיג את אותה תוצאה כמו שרשור רשימות:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals_to_add = ['duck', 'pig', 'zebra']\n", + "animals = animals + animals_to_add\n", + "print(animals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "אבל אחד היתרונות המשמעותיים ב־extend
הוא שניתן להעביר לה כל iterable שהוא.
\n",
+ "הפעולה extend
תפרק את ה־iterable ותוסיף כל איבר בנפרד לרשימה המקורית: \n",
+ "
\n",
+ " תרגול:\n",
+ " כתבו פונקציה שמקבלת רשימה, ומחזירה רשימה המכילה את הרשימה המקורית, ומיד אחריה את אותה רשימה בסדר הפוך.
\n",
+ " לדוגמה: עבור הרשימה [1, 2, 3]
תוחזר הרשימה: [1, 2, 3, 3, 2, 1]
\n",
+ "
\n",
+ "כאן לא תמצאו הפתעות מיוחדות. הפעולה count
סופרת את כמות האיברים שזהים לאיבר שהעברתם לה כארגומנט.
\n",
+ "נשמע לכם מוכר? נכון! למחרוזות יש פעולה עם אותו שם שעושה בדיוק אותו דבר.\n",
+ "
\n",
+ "גם הפעולה הזו אמורה לצלצל לכם מוכר.
\n",
+ "הפעולה index
מוצאת את המופע הראשון של האיבר שהעברתם לה כארגומנט.
\n",
+ "וכן, גם הפעם למחרוזות יש פעולה עם אותו שם שעושה בדיוק אותו דבר.\n",
+ "
\n",
+ " כמו בפעולת index
במחרוזת, גם כאן הפעולה תקפיץ שגיאה במידה והערך לא נמצא.\n",
+ "
\n",
+ " תרגול:\n",
+ " כתבו פונקציה שמקבלת רשימה, ומחזירה את המיקום של המופע האחרון של האיבר שמופיע במקום 0 ברשימה.
\n",
+ " לדוגמה, עבור הרשימה [1, 2, 3, 5, 1, 2]
החזירו 4, מכיוון ש־1 מופיע פעם אחרונה במקום 4 ברשימה.\n",
+ "
\n",
+ "הפעם נשתמש בפעולה remove
, שבניגוד לפעולה pop
מוחקת איבר לפי הערך שלו ולא לפי המיקום שלו.
\n",
+ "שימו לב שהפעולה תמחק את האיבר הראשון שהיא תמצא, ולא את כל המופעים שלו.\n",
+ "
\n",
+ " תרגול:\n",
+ " קבלו פונקציה שמקבלת רשימה של חיות, ומחזירה רשימה ללא מופעים של החיות camel, rabbit או pig.
\n",
+ " לדוגמה, עבור הרשימה: ['camel', 'camel', 'dove', 'pig', 'camel']
תוחזר הרשימה: ['dove']
\n",
+ "
\n",
+ "אחת הפעולות הנוחות ביותר שאפשר למצוא בפייתון היא sort
, שמסדרת לנו את האיברים ברשימה.
\n",
+ "אם האיברים הם מחרוזות, הסדר יהיה סדר לקסיקוגרפי (לפי א\"ב).
\n",
+ "אם האיברים ברשימה הם מספרים (שלמים, עשרוניים או גם וגם), הסדר יהיה סדר עולה מתמטית.
\n",
+ "אם הרשימה מורכבת מסוגים שונים של איברים שאין ביניהם הגדרת שיוויון ברורה (כמו מספרים ומחרוזות), פעולת המיון תכשל ותזרוק שגיאה.\n",
+ "
\n",
+ " טעות נפוצה היא להכניס את התוצאה של sort
חזרה למשתנה.
\n",
+ " מכיוון שהפעולה sort
משנה את ערך המשתנה במקום ולא מחזירה ערך, השמה חזרה למשתנה תמחק את ערכו.\n",
+ "
\n",
+ " תרגול:\n",
+ " קבלו מהמשתמש 10 מספרים. מצאו מה הערך השלישי הכי גדול.
\n",
+ " לדוגמה, עבור הקלט הבא: 5, 1, 6, 2, 3, 4, 8, 7, 10, 9
, החזירו 8.\n",
+ "
\n",
+ " תרגול:\n",
+ " קראו בתיעוד של פייתון על הפעולה insert
השייכת לרשימה.
\n",
+ " הוסיפו דג מימין לכריש (shark) שברשימת animals.\n",
+ "
\n",
+ " כתבו פונקציה שמקבלת רשימה של רשימות, ומחזירה רשימה שטוחה והפוכה של כל האיברים.
\n",
+ " לדוגמה: עבור הרשימה [[1, 2, 3], [4, 5, 6]]
החזירו [6, 5, 4, 3, 2, 1]
.\n",
+ "
\n",
+ "המילה Mutable נגזרת מהמילה Mutate, והמשמעות שלה היא \"משהו שאפשר לשנות\".
\n",
+ "אנחנו נשתמש בה עבור סוגי נתונים שמיועדים לכך שישנו אותם, למשל יוסיפו אליהם איברים או יחסירו מהם איברים.
\n",
+ "משמעות המילה Immutable היא \"משהו שאי אפשר לשנות\", נתון שאמור להיות קבוע אחרי יצירתו.
\n",
+ "שינוי ערך שהוא Immutable משנה את המהות שלו, ויגרום לו להחשב ערך אחר לגמרי.\n",
+ "
\n",
+ "נדמיין ארנק שבתוכו שטרות – ניתן להוסיף אליו שטרות או להוציא ממנו שטרות, אבל הארנק יישאר אותו ארנק.
\n",
+ "מכיוון שניתן לשנות את המצב של הארנק בלי לפגוע במהות שלו, ניתן להגיד שארנק הוא Mutable.
\n",
+ "לעומת זאת, אם אקח את אחד השטרות שנמצאים בתוך הארנק, לא אוכל לשנות בו משהו בלי שהוא יאבד את המהות שלו.
\n",
+ "שינוי באחד המאפיינים של השטר, כמו המספר שכתוב עליו, יגרור שינוי מהותי שיהפוך אותו לדבר אחר לחלוטין.
\n",
+ "ניתן להגיד שהשטר הוא Immutable, בלתי ניתן לשינוי.\n",
+ "
\n",
+ "הערכים ה־Mutable שנכיר בקורס הם מעין \"מכולות\" שמכילות ערכים אחרים.
\n",
+ "עד כה, אנו מכירים סוג ערך אחד שהוא Mutable – רשימה.\n",
+ "
\n", + "כדי להבין טוב יותר את הנושא, נעצור לרגע כדי להבין איך ערכים עובדים מאחורי הקלעים בפייתון.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "כשאנחנו יוצרים ערך כלשהו, פייתון מקצה עבורו מקום בזיכרון המחשב ושומרת שם את הערך.
\n",
+ "מאותו רגע לאותו ערך יש כתובת, שהיא מספר שמייצג איפה הוא נמצא בזיכרון.
\n",
+ "הכתובת של ערך נשארת זהה מרגע שהוא נוצר ועד סוף חייו.\n",
+ "
\n",
+ "בשורה למעלה הגדרנו את הערך 9876543.
\n",
+ "אפילו שלא עשינו עליו פעולה מתוחכמת ולא שמרנו אותו במשתנה, פייתון תשמור את הערך הזה בזיכרון המחשב.
\n",
+ "לערך 9876543 יש כתובת עכשיו.\n",
+ "
\n",
+ "כשאנחנו מגדירים משתנה חדש, אנחנו בסך־הכל יוצרים קישור בין שם המשתנה לבין הכתובת של הערך שהשמנו לתוכו.
\n",
+ "תוכלו לדמיין משתנה כסוג של לייזר שמצביע על מקום מסוים במפה – ראש הלייזר הוא שם המשתנה, והמקום במפה הוא כתובת הערך שלו.\n",
+ "
\n",
+ "בשורה למעלה \"קשרנו\" את השם name לכתובת של הערך המספרי 12345.
\n",
+ "המשתנה name לא \"מכיל\" את הערך 12,345, אלא רק מצביע על הכתובת שבה הערך 12,345 מאוחסן.\n",
+ "
\n",
+ "הפונקציה id
מקבלת כארגומנט ערך, ומחזירה מספר שמייצג את הכתובת שלו – המיקום של הערך בזיכרון.
\n",
+ "נראה דוגמה:\n",
+ "
\n", + "הדוגמה האחרונה מבהירה שעבור ערכים שונים, אפילו אם אותו שם משתנה מצביע עליהם, יש כתובות שונות.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "number = 100000\n", + "print(\"ID before: \" + str(id(number)))\n", + "number = number + 1\n", + "print(\"ID after: \" + str(id(number)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "בדוגמה הגדלנו את ערך המשתנה number מ־100,000 ל־100,001.
\n",
+ "החלק החשוב לזכור בדוגמה הזו היא שההעלאה מ־100,000 ל־100,001 לא באמת \"שינתה את הערך ששמור במשתנה\", אלא גרמה למשתנה להצביע לכתובת אחרת של ערך אחר.\n",
+ "
\n",
+ "בשורה הראשונה \"קשרנו\" את שם המשתנה number לערך 100,000, ולכן כשביקשנו את id(number)
למעשה ביקשנו לדעת את הכתובת של 100,000.
\n",
+ "בשורה השנייה \"קשרנו\" את שם המשתנה number לערך 100,001, ולכן כשביקשנו את id(number)
למעשה ביקשנו לדעת את הכתובת של 100,001.\n",
+ "
\n",
+ " עבור שתי השורות הראשונות מודפסת הכתובת של הערך הראשון שיצרנו, 100,000.
\n",
+ " עבור שתי השורות האחרונות מודפסת הכתובת של הערך השני שיצרנו, 100,001.\n",
+ "
\n", + "חשוב לדעת שהתייחסות לאותו ערך פעם נוספת עלולה ליצור מופע חדש שלו, שיאוחסן בכתובת אחרת:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"ID of number ({number}): \" + str(id(number)))\n", + "number2 = 100001\n", + "print(f\"ID of number2 ({number2}): \" + str(id(number2)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "אבל השמה של משתנה אחד למשתנה אחר תגרום לכך ששני המשתנים יפנו לאותה כתובת:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"ID of number: \" + str(id(number)))\n", + "number3 = number\n", + "print(\"ID of number2: \" + str(id(number3)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "ניתן לדמיין את המצב כמו שני ראשי לייזר שמצביעים לאותה נקודה על המפה,
\n",
+ "או כמו מגירה שמכילה ערך ושהדביקו עליה שתי מדבקות עם שמות שונים.\n",
+ "
\n",
+ "נבדוק האם שינוי של ערך בתוך רשימה יגרום לפייתון לבנות רשימה חדשה.
\n",
+ "אם פייתון יבנה רשימה חדשה אחרי שינוי הערך, נוכל לראות זאת בקלות לפי השינוי במיקום של הרשימה בזיכרון.\n",
+ "
\n",
+ "בדוגמה שינינו ערך ברשימה ששמה my_list, וראינו שהמיקום שלה לא משתנה.
\n",
+ "זה מה שאנחנו מצפים מערך שהסוג שלו הוא Mutable – ניתן לשנות אותו.
\n",
+ "
\n", + "נעשה את הניסיון הבא:
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "str1 = \"Puns are the highest form of literature.\"\n", + "str2 = str1\n", + "str2 = str2 + \"\\n\\t - Alfred Hitchcock\"\n", + "\n", + "print(str1)\n", + "print('-' * len(str1))\n", + "print(str2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "עם הידע החדש שצברנו, נוכל לראות ש־str1 ו־str2 מצביעים למקומות שונים, בגלל ההשמה בשורה 3.\n", + "
\n", + "\n", + "אבל ברשימות אפשר לשנות את הערכים גם בלי לבצע השמה. מה קורה אז?\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list1 = [2, 8, 20, 28, 50, 82]\n", + "list2 = list1\n", + "list2.append(126)\n", + "\n", + "print(list1)\n", + "print('-' * len(str(list1)))\n", + "print(list2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "במקרה הזה, גרמנו ל־list2 להצביע לאותו מקום ש־list1 מצביעה עליו.
\n",
+ "מהסיבה הזו, שינוי של list2 משפיע גם על list1, ושינוי של list1 ישפיע גם על list2.\n",
+ "
\n",
+ " כדי \"להתגבר\" על זה, צריך להגיד לפייתון במוצהר שאנחנו מעוניינים ביצירת רשימה חדשה.
\n",
+ " ניתן לעשות את זה על־ידי קריאה לפעולה list.copy()
:\n",
+ "
\n", + "נגדיר פונקציה שמקבלת מחרוזת, ומוסיפה לה בסוף את האות Z:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def append_to_string(my_string):\n", + " print('\\t--- Inside the function now ---')\n", + " print(f'\\tFunction got value: {my_string}, with id: {id(my_string)}.')\n", + " my_string = my_string + 'Z'\n", + " print(f'\\tChanged my_string to be {my_string}, with id: {id(my_string)}.')\n", + " print('\\t--- Finished to run the function now ---')\n", + "\n", + "s = 'Hello'\n", + "print(f'Before calling the function: s = {s}, with id: {id(s)}.')\n", + "append_to_string(s)\n", + "print(f'After calling the function: s = {s}, with id: {id(s)}.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "מה קרה בפועל? למה המחרוזת לא השתנתה גם מחוץ לפונקציה?\n", + "
\n", + "\n",
+ "הערך שהועבר לפרמטר של הפונקציה היה הכתובת של s, שעכשיו גם my_string מצביעה עליו.
\n",
+ "ברגע שביצענו את ההשמה my_string = my_string + 'Z'
, יצרנו באגף הימני ערך חדש, ושמנו ב־my_string את הכתובת שלו.
\n",
+ "המשתנה my_string מצביע כרגע לכתובת של ערך אחר, בזמן שהמשתנה s עדיין מצביע על הערך המקורי.\n",
+ "
\n",
+ "במקרה הזה, הפונקציה לא שינתה את הערך של המחרוזת שהעברנו לה כארגומנט.
\n",
+ "גם אם מאוד היינו רוצים לעשות את זה – זה לא אפשרי, מכיוון שמחרוזות הן Immutable.
\n",
+ "
\n", + "ננסה לעשות אותו דבר עם רשימה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def append_to_list(my_list):\n", + " print('\\t--- Inside the function now ---')\n", + " print(f'\\tFunction got value: {my_list}, with id: {id(my_list)}.')\n", + " my_list = my_list + [126]\n", + " print(f'\\tChanged my_string to be {my_list}, with id: {id(my_list)}.')\n", + " print('\\t--- Finished to run the function now ---')\n", + "\n", + "l = [2, 8, 20, 28, 50, 82]\n", + "print(f'Before calling the function: l = {l}, with id: {id(l)}.')\n", + "append_to_list(l)\n", + "print(f'After calling the function: l = {l}, with id: {id(l)}.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "ההתרחשות הייתה זהה למה שקרה עם מחרוזות!
\n",
+ "זה קרה מכיוון שגם פה, דרסנו את my_list כך שיצביע לרשימה חדשה שיצרנו.
\n",
+ "בצד ימין של ההשמה, יצרנו רשימה חדשה שמכילה את האיברים 2, 8, 20, 28, 50, 82, 126.
בעצם ההשמה ביקשנו מ־my_list שבתוך הפונקציה להפנות לכתובת של הרשימה החדשה.
\n",
+ "ננסה להשתמש בפעולה של צירוף איבר חדש לרשימה, list.append(item)
, עליה למדנו השבוע:\n",
+ "
\n",
+ "הצלחנו!
\n",
+ "הרשימה השתנתה גם בתוך הפונקציה וגם מחוץ לה.
\n",
+ "אפשר ללמוד מהדוגמה הזו שכשאנחנו מבצעים השמה לשם משתנה מסוים, אנחנו משנים את הכתובת שאליה הצביע שם המשתנה לכתובת חדשה, ולא \"עורכים\" את התוכן שלו.
\n",
+ "
\n",
+ "כשלמדנו פונקציות, אחד הדגשים שעלו הוא זה שפונקציה היא קטע קוד עצמאי.
\n",
+ "ככזו, פונקציה בדרך־כלל לא תשנה ערכים של משתנים שלא היא הגדירה.
\n",
+ "לדוגמה, קטע הקוד שמופיע למעלה ועורך את המשתנה l
שהוגדר מחוץ לפונקציה, נחשב הרגל רע.\n",
+ "
\n", + " הנה קטע הקוד מלמעלה בלי ההדפסות המסרבלות:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 8, 20, 28, 50, 82, 126]\n" + ] + } + ], + "source": [ + "def append_to_list(my_list):\n", + " my_list.append(126)\n", + "\n", + "l = [2, 8, 20, 28, 50, 82]\n", + "append_to_list(l)\n", + "print(l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " ננסה לרשום קוד זהה, רק שהפעם הפונקציה לא תערוך את המשתנה l
:\n",
+ "
\n", + " צורת הכתיבה הזו מבטיחה לנו מספר יתרונות:\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " ברוח השיעור על העובדה שרשימות הן Mutable, הגיע הזמן להכיר את האח דל־התקציב שלהן: tuple
.
\n",
+ " סוג הנתונים tuple לא מרגש במיוחד – הוא למעשה סוג של רשימה שאי אפשר לשנות. Immutable list, אם תרצו.\n",
+ "
\n", + " נגדיר משתנה מסוג tuple באמצעות סוגריים עגולים:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals = ('dog', 'fish', 'horse')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " כמו ברשימה, ניתן לקבל איברים שנמצאים ב־tuple על־ידי פנייה למיקום שלהם:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "first_animal = animals[0]\n", + "print(f\"The first animal is {first_animal}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " ניסיון לשנות את ה־tuple לא יצליח, מן הסתם. Immutable, זוכרים?\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animals[1] = 'pig'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " יצירת tuple ריק תכתב כך:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "my_tuple = tuple()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " ועבור יצירת tuple עם איבר אחד בלבד, נכתוב את האיבר ואז פסיק אחריו, כדי שפייתון לא תפרש את הביטוי כסוגריים רגילים:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [], + "source": [ + "my_tuple = (4, )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " תרגול:\n",
+ " כתבו פונקצייה שמשתמשת ב־dir()
, ומחזירה את כל הפעולות שיש ב־list ואין ב־tuple.
\n",
+ " בדקו גם אילו פעולות יש ב־tuple ואין ב־list.
\n",
+ " בשתי ההשוואות, התעלמו מפעולות שמתחילות בתו קו תחתון.\n",
+ "
\n", + " אם tuple מעניק לי פחות חופש פעולה, למה להשתמש בו מלכתחילה?\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "מונחים
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " פונקציית גיבוב היא פונקציה המקבלת קלט כלשהו ומחזירה ערך באורך קבוע.
\n",
+ " קיימות פונקציות גיבוב רבות, ולהן שימושים מגוונים.\n",
+ "
\n", + " נמנה מספר תכונות נפוצות שקיימות בפונקציות גיבוב:\n", + "
\n", + " \n", + "\n",
+ " בתרגיל זה נממש גרסה פשוטה של פונקציית גיבוב (hash function).
\n",
+ " פונקציית הגיבוב שלנו תקבל מחרוזת ותחזיר תמיד פלט באורך זהה.\n",
+ "
\n",
+ " תחילה נכיר את הפונקציה ord(תו)
.
\n",
+ " פונקציה זו מקבלת תו, ומחזירה ערך מספרי המייצג אותו:
\n",
+ "
\n",
+ "פונקציית הגיבוב שלנו תעבוד באופן הבא:
\n",
+ "
ord(letter)
ונכפיל במשתנה העזר hash.\n", + "פונקציית הגיבוב שיצרנו מחזירה תמיד ערכים באורך קבוע (בין 0 ל־100297) כפי שפונקציית גיבוב צריכה להחזיר (לאו דווקא באורך זה, אבל הפלט חייב להיות באורך קבוע).\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " דוגמה:
\n",
+ "
myhash('aba')
\n",
+ " החישוב התבצע כך:
\n",
+ "
temp_hash = 1
temp_hash = (temp_hash*ord('a')*1) % 397643
\n",
+ "# temp_hash = (1*97*1) % 397643 = 97\n", + " שימו לב שכאן הכפלנו ב־1, כיון שמיקום האות הוא 0 ואנו מכפילים\n", + " באינדקס האות הבאה.\n", + "
\n", + "\n", + "temp_hash = (temp_hash*ord('b')*2) % 397643
\n",
+ "# temp_hash = (97*98*2) % 397643 = 19012\n",
+ "temp_hash = (temp_hash*ord('a')*3) % 397643
\n",
+ "# temp_hash = (19012*97*3) % 397643 = 363133\n",
+ "return temp_hash % 100297
\n",
+ "# temp_hash = 363133 % 100297 = 62242"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ " ממשו את פונקציית הגיבוב.
\n",
+ " על מנת לבדוק את עצמכם ודאו שקיבלתם את הערכים הבאים עבור המחרוזות הבאות:
\n",
+ "
myhash('python course')
myhash('hashing is sababa')
myhash('i calculate hashes for fun')
\n",
+ " שימו לב שזוהי פונקציית גיבוב מומצאת.
\n",
+ " אנחנו לעולם לא נשתמש בפונקציות גיבוב שהמצאנו בסביבות אמיתיות שאנחנו מתכנתים(!), משום שדבר כזה יסכן בוודאות את המשתמשים במערכת.
\n",
+ " זה עולם שלם שנחקר רבות, ואנחנו תמיד נשתמש רק בפונקציות גיבוב שנחקרו ופורסמו מטעמי המוסדות הרלוונטיים.\n",
+ "
\n",
+ " נזכיר את החוקים של המשחק המוכר איקס־עיגול:
\n",
+ "
\n",
+ " את הלוח נייצג באמצעות רשימה של רשימות.
\n",
+ " כל רשימה תייצג שורה בלוח שלנו: הרשימה במיקום 0 תייצג את השורה הראשונה בלוח, הרשימה בשורה 1 את השורה השנייה וכך הלאה.
\n",
+ " הרשימות המייצגות את השורות יהיו רשימות של תווים, כאשר בכל תא יהיה אחד מבין התווים האפשריים – 'O', 'X' או '-'\n",
+ "
\n", + " לדוגמה, כך נראה לוח ריק:\n", + "
\n", + " \n", + "[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]\n", + " \n", + "\n", + " נוח לדמיין את הרשימה הזו כתובה במאונך:\n", + "
\n", + "\n", + "\n", + "[\n", + " ['-', '-', '-'],\n", + " ['-', '-', '-'],\n", + " ['-', '-', '-']\n", + "]\n", + "\n", + " \n", + "\n", + " כעת נראה איך נראה הלוח כאשר יש 'X' באלכסון:\n", + "
\n", + "\n", + "\n", + "[\n", + " ['X', '-', '-'],\n", + " ['-', 'X', '-'],\n", + " ['-', '-', 'X']\n", + "]\n", + "\n", + "\n", + " וללא ההדפסה לאורך:\n", + "
\n", + "\n", + "[['X', '-', '-'], ['-', 'X', '-'], ['-', '-', 'X']]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " תחילה נממש פונקציה המקבלת את הלוח ובודקת האם יש מנצח כלשהו \n", + " (X או O),\n", + " ומחזירה את האות של המנצח\n", + " ('X' או 'O')\n", + " אם יש מנצח ו־'' (מחרוזת ריקה)\n", + " אחרת.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# check_board(board) כתבו את הפונקציה שלכם כאן" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " לפני שתמשיכו הלאה חשוב לוודא שהפונקציה שכתבתם עובדת.
\n",
+ " כתבו בדיקות עבור המקרים הבאים:\n",
+ "
\n", + " סך־הכל תצטרכו לכתוב 10 בדיקות.\n", + "
\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור אלכסון ראשי" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור אלכסון משני" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור טור שמאלי" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור טור אמצעי" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור טור ימני" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור שורה עליונה" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור שורה אמצעית" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור שורה תחתונה" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור לוח מלא ללא ניצחון" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# בדיקה עבור לוח לא מלא ללא ניצחון" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### פונקציות לבדיקת תקינות קלט" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " במהלך המשחק אנו נקלוט מהשחקנים במשחק (המשתמשים) את המקומות בלוח בהם הם ירצו למקם את האות שלהם.
\n",
+ " מקומות אלו יהיו שני מספרים בתחום 0–2 המציינים את השורה והעמודה בה יש למקם את האות.
\n",
+ " לדוגמה, עבור:\n",
+ "
\n", + " נמקם את האות המתאימה לשחקן, נניח X, בשורה 1 ובעמודה 2, באופן הבא:\n", + "
\n", + "\n", + "[['-', '-', '-'], ['-', '-', 'X'], ['-', '-', '-']]\n", + "\n", + "\n", + " זכרו כי הספירה מתחילה מ־0 ולכן מדובר בשורה האמצעית ובעמודה הימנית.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " כעת כתבו פונקציה המקבלת את הלוח, ואת התו שמייצג את השחקן ('X' או 'O'). כמו כן, הפונקציה תקלוט מהמשתמש שני מספרים.
\n",
+ " הפונקציה תבדוק האם התנאים הבאים מתקיימים, במידה והם מתקיימים היא תמקם את האות הנתונה במיקום המבוקש, ותעדכן את הלוח:
\n",
+ "
\n",
+ " שימו לב, עליכם לחייב את המשתמש להכניס ערכים חוקיים. כלומר, המשחק לא ימשיך עד אשר יתקבל קלט תקין.
\n",
+ " כאשר נגלה בשלב מוקדם יותר שהלוח לא ניתן יותר למילוי – המשחק יסתיים.\n",
+ "
\n", + "לוח לדוגמה:\n", + "
\n", + "\n", + "\n", + "board = [['-', '-', '-'], ['-', 'O', 'X'], ['-', '-', '-']]\n", + "\n", + "\n", + "\n", + " הזנה חוקית:\n", + "
\n", + "\n", + "make_turn('X', board)
\n",
+ "\n",
+ "\n", + " הזנה לא חוקית:\n", + "
\n", + "\n", + "\n", + " שימו לב שלאחר כל פעולה אנו מדפיסים את הלוח, בין אם הצליחה ובין אם לא.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# make_turn(player_char,board) כתבו את הפונקציה שלכם כאן" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " בונוס: ממשו פונקציה שמדפיסה את הלוח לאורך.\n", + "
\n", + "\n", + "print_board(board)
\n",
+ "\n",
+ "\n",
+ " כאמור המשחק ממשיך כל עוד אין מנצח ונותר מקום פנוי בלוח.
\n",
+ " נשים לב כי מספר המהלכים החוקיים יכול להיות לכל היותר כגודל הלוח.
\n",
+ " כלומר – אם לא הוכרז מנצח במהלך המשחק, המשחק ייגמר לאחר 9 מהלכים עבור לוח בגודל $3\\times3$.
\n",
+ " נספור את כמות המהלכים החוקיים במשחק. עבור מספר מהלך זוגי (0, 2, 4, ...) ישחק השחקן O, ועבור מספרי מהלך אי־זוגיים ישחק השחקן X.
\n",
+ " נתאר את מהלך המשחק בפסאודו־קוד:
\n",
+ "
\n", + " ממשו את המשחק על־פי הפונקציות שמימשתם ותיאור מהלך המשחק.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# tic_tac_toe()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " כעת שחקו עם בני משפחה וחברים ;)\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## בנק 2.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " מנהלי הבנק היו מאוד מרוצים מהתוכנה הקודמת לניהול בנק שכתבתם וכעת היו רוצים לשפר אותה.
\n",
+ " תחילה הם הביעו דאגה מחוזק הסיסמאות. מנגנון הסיסמאות הקודם היה חלש ומנהלי הבנק מפחדים שיעשה בו שימוש לרעה.
\n",
+ " שמועות מתפשטות מאוד מהר ומנהלי הבנק שמעו שמימשתם גרסה לפונקציית גיבוב. הם מעוניינים לעשות בה שימוש במנגנון הסיסמאות החדש.\n",
+ "
\n", + " מנגנון הסיסמאות ינוהל באופן הבא:\n", + "
\n", + "\n", + "\n",
+ " כל סיסמה של משתמש תשמר בקובץ בצורה: username:62242,
\n",
+ " כאשר username הוא שם המשתמש שנרשם בפתיחת החשבון, ו־62242 הוא תוצאת ה־hash על הסיסמה שבחר.\n",
+ "
בסעיף זה נממש את פונקציית פתיחת חשבון הבנק.
\n",
+ " הפונקציה תקבל שם משתמש וסיסמה, ותיצור רשומה חדשה בקובץ הסיסמאות עבור המשתמש שביקש להצטרף לבנק.
\n",
+ " כיוון שהבנק שלנו לא עבר לעבוד עם מספרי חשבון, עלינו לוודא שלא ששם המשתמש שנבחר לא קיים כבר בבנק, אם קיים כזה נדפיס שגיאה ולא נבצע דבר.
\n",
+ " אם לא קיים שם משתמש שכזה, נחשב את ה־hash של הסיסמה שהזין, ונוסיף לסוף הקובץ רשומה חדשה בייצוג שצוין בתחילת השאלה.\n",
+ "
\n", + "תוכן קובץ הסיסמאות (לצורך הדוגמה):\n", + "
\n", + "\n", + "FreddieMercury:56443register_to_bank('FreddieMercury', 'ILoveQueen')
register_to_bank('Simba', 'ILoveNala')
\n", + " תוכן קובץ הסיסמאות כעת:\n", + "
\n", + "\n", + "FreddieMercury:56443ממשו את פונקציית הרישום.
\n", + "רמזים:
\n", + "\n", + "\n",
+ " בעקבות השיפורים בחוזק הסיסמאות הצטרפו הרבה לקוחות לבנק.
\n",
+ " המנהלים מרוצים וכעת רוצים שתממשו עבורם מערכת הזדהות שעובדת עם קובץ הסיסמאות.\n",
+ "
\n", + " מערכת ההזדהות תעבוד באופן הבא:\n", + "
\n", + "\n", + "\n",
+ " מערכת ההזדהות הינה פונקציה המקבלת שם משתמש וסיסמה.
\n",
+ " היא מחזירה True אם הזיהוי הצליח, ו־False אחרת.\n",
+ "
\n", + " תוכן קובץ הסיסמאות (לצורך הדוגמה):\n", + "
\n", + "\n", + "authenticate('FreddieMercury', 'ILoveQueen')
authenticate('FreddieMercury', 'LetItBe')
authenticate('FreddieMercury', 'HeyJude')
authenticate('FreddieMercury', 'IHatePasswords!')
authenticate('Simba', 'ILoveNala')
\n", + " תוכן קובץ הסיסמאות כעת:\n", + "
\n", + "\n", + "\n", + " ממשו את מערכת ההזדהות.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# authenticate(username,password) ממשו את הפונקציה כאן" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/week3/images/binary-png-representation.png b/week3/images/binary-png-representation.png new file mode 100644 index 0000000..4c1a7e1 Binary files /dev/null and b/week3/images/binary-png-representation.png differ diff --git a/week3/images/exercise.svg b/week3/images/exercise.svg new file mode 100644 index 0000000..819a775 --- /dev/null +++ b/week3/images/exercise.svg @@ -0,0 +1,48 @@ + + + diff --git a/week3/images/logo.png b/week3/images/logo.png new file mode 100644 index 0000000..0f1d548 Binary files /dev/null and b/week3/images/logo.png differ diff --git a/week3/images/textual-csv-representation.png b/week3/images/textual-csv-representation.png new file mode 100644 index 0000000..849f213 Binary files /dev/null and b/week3/images/textual-csv-representation.png differ diff --git a/week3/images/tip.png b/week3/images/tip.png new file mode 100644 index 0000000..a563b03 Binary files /dev/null and b/week3/images/tip.png differ diff --git a/week3/images/warning.png b/week3/images/warning.png new file mode 100644 index 0000000..4863041 Binary files /dev/null and b/week3/images/warning.png differ diff --git a/week3/images/while-flow.svg b/week3/images/while-flow.svg new file mode 100644 index 0000000..abae954 --- /dev/null +++ b/week3/images/while-flow.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/week3/images/while-song.svg b/week3/images/while-song.svg new file mode 100644 index 0000000..d1124fe --- /dev/null +++ b/week3/images/while-song.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/week3/resources/cereal.csv b/week3/resources/cereal.csv new file mode 100644 index 0000000..815c27c --- /dev/null +++ b/week3/resources/cereal.csv @@ -0,0 +1,78 @@ +name,mfr,type,calories,protein,fat,sodium,fiber,carbo,sugars,potass,vitamins,shelf,weight,cups,rating +100% Bran,N,C,70,4,1,130,10,5,6,280,25,3,1,0.33,68.402973 +100% Natural Bran,Q,C,120,3,5,15,2,8,8,135,0,3,1,1,33.983679 +All-Bran,K,C,70,4,1,260,9,7,5,320,25,3,1,0.33,59.425505 +All-Bran with Extra Fiber,K,C,50,4,0,140,14,8,0,330,25,3,1,0.5,93.704912 +Almond Delight,R,C,110,2,2,200,1,14,8,-1,25,3,1,0.75,34.384843 +Apple Cinnamon Cheerios,G,C,110,2,2,180,1.5,10.5,10,70,25,1,1,0.75,29.509541 +Apple Jacks,K,C,110,2,0,125,1,11,14,30,25,2,1,1,33.174094 +Basic 4,G,C,130,3,2,210,2,18,8,100,25,3,1.33,0.75,37.038562 +Bran Chex,R,C,90,2,1,200,4,15,6,125,25,1,1,0.67,49.120253 +Bran Flakes,P,C,90,3,0,210,5,13,5,190,25,3,1,0.67,53.313813 +Cap'n'Crunch,Q,C,120,1,2,220,0,12,12,35,25,2,1,0.75,18.042851 +Cheerios,G,C,110,6,2,290,2,17,1,105,25,1,1,1.25,50.764999 +Cinnamon Toast Crunch,G,C,120,1,3,210,0,13,9,45,25,2,1,0.75,19.823573 +Clusters,G,C,110,3,2,140,2,13,7,105,25,3,1,0.5,40.400208 +Cocoa Puffs,G,C,110,1,1,180,0,12,13,55,25,2,1,1,22.736446 +Corn Chex,R,C,110,2,0,280,0,22,3,25,25,1,1,1,41.445019 +Corn Flakes,K,C,100,2,0,290,1,21,2,35,25,1,1,1,45.863324 +Corn Pops,K,C,110,1,0,90,1,13,12,20,25,2,1,1,35.782791 +Count Chocula,G,C,110,1,1,180,0,12,13,65,25,2,1,1,22.396513 +Cracklin' Oat Bran,K,C,110,3,3,140,4,10,7,160,25,3,1,0.5,40.448772 +Cream of Wheat (Quick),N,H,100,3,0,80,1,21,0,-1,0,2,1,1,64.533816 +Crispix,K,C,110,2,0,220,1,21,3,30,25,3,1,1,46.895644 +Crispy Wheat & Raisins,G,C,100,2,1,140,2,11,10,120,25,3,1,0.75,36.176196 +Double Chex,R,C,100,2,0,190,1,18,5,80,25,3,1,0.75,44.330856 +Froot Loops,K,C,110,2,1,125,1,11,13,30,25,2,1,1,32.207582 +Frosted Flakes,K,C,110,1,0,200,1,14,11,25,25,1,1,0.75,31.435973 +Frosted Mini-Wheats,K,C,100,3,0,0,3,14,7,100,25,2,1,0.8,58.345141 +Fruit & Fibre Dates & Walnuts & and Oats,P,C,120,3,2,160,5,12,10,200,25,3,1.25,0.67,40.917047 +Fruitful Bran,K,C,120,3,0,240,5,14,12,190,25,3,1.33,0.67,41.015492 +Fruity Pebbles,P,C,110,1,1,135,0,13,12,25,25,2,1,0.75,28.025765 +Golden Crisp,P,C,100,2,0,45,0,11,15,40,25,1,1,0.88,35.252444 +Golden Grahams,G,C,110,1,1,280,0,15,9,45,25,2,1,0.75,23.804043 +Grape Nuts Flakes,P,C,100,3,1,140,3,15,5,85,25,3,1,0.88,52.076897 +Grape-Nuts,P,C,110,3,0,170,3,17,3,90,25,3,1,0.25,53.371007 +Great Grains Pecan,P,C,120,3,3,75,3,13,4,100,25,3,1,0.33,45.811716 +Honey Graham Ohs,Q,C,120,1,2,220,1,12,11,45,25,2,1,1,21.871292 +Honey Nut Cheerios,G,C,110,3,1,250,1.5,11.5,10,90,25,1,1,0.75,31.072217 +Honey-comb,P,C,110,1,0,180,0,14,11,35,25,1,1,1.33,28.742414 +Just Right Crunchy Nuggets,K,C,110,2,1,170,1,17,6,60,100,3,1,1,36.523683 +Just Right Fruit & Nut,K,C,140,3,1,170,2,20,9,95,100,3,1.3,0.75,36.471512 +Kix,G,C,110,2,1,260,0,21,3,40,25,2,1,1.5,39.241114 +Life,Q,C,100,4,2,150,2,12,6,95,25,2,1,0.67,45.328074 +Lucky Charms,G,C,110,2,1,180,0,12,12,55,25,2,1,1,26.734515 +Maypo,A,H,100,4,1,0,0,16,3,95,25,2,1,1,54.850917 +Muesli Raisins & Dates & Almonds,R,C,150,4,3,95,3,16,11,170,25,3,1,1,37.136863 +Muesli Raisins & Peaches & Pecans,R,C,150,4,3,150,3,16,11,170,25,3,1,1,34.139765 +Mueslix Crispy Blend,K,C,160,3,2,150,3,17,13,160,25,3,1.5,0.67,30.313351 +Multi-Grain Cheerios,G,C,100,2,1,220,2,15,6,90,25,1,1,1,40.105965 +Nut&Honey Crunch,K,C,120,2,1,190,0,15,9,40,25,2,1,0.67,29.924285 +Nutri-Grain Almond-Raisin,K,C,140,3,2,220,3,21,7,130,25,3,1.33,0.67,40.692320 +Nutri-grain Wheat,K,C,90,3,0,170,3,18,2,90,25,3,1,1,59.642837 +Oatmeal Raisin Crisp,G,C,130,3,2,170,1.5,13.5,10,120,25,3,1.25,0.5,30.450843 +Post Nat. Raisin Bran,P,C,120,3,1,200,6,11,14,260,25,3,1.33,0.67,37.840594 +Product 19,K,C,100,3,0,320,1,20,3,45,100,3,1,1,41.503540 +Puffed Rice,Q,C,50,1,0,0,0,13,0,15,0,3,0.5,1,60.756112 +Puffed Wheat,Q,C,50,2,0,0,1,10,0,50,0,3,0.5,1,63.005645 +Quaker Oat Squares,Q,C,100,4,1,135,2,14,6,110,25,3,1,0.5,49.511874 +Quaker Oatmeal,Q,H,100,5,2,0,2.7,-1,-1,110,0,1,1,0.67,50.828392 +Raisin Bran,K,C,120,3,1,210,5,14,12,240,25,2,1.33,0.75,39.259197 +Raisin Nut Bran,G,C,100,3,2,140,2.5,10.5,8,140,25,3,1,0.5,39.703400 +Raisin Squares,K,C,90,2,0,0,2,15,6,110,25,3,1,0.5,55.333142 +Rice Chex,R,C,110,1,0,240,0,23,2,30,25,1,1,1.13,41.998933 +Rice Krispies,K,C,110,2,0,290,0,22,3,35,25,1,1,1,40.560159 +Shredded Wheat,N,C,80,2,0,0,3,16,0,95,0,1,0.83,1,68.235885 +Shredded Wheat 'n'Bran,N,C,90,3,0,0,4,19,0,140,0,1,1,0.67,74.472949 +Shredded Wheat spoon size,N,C,90,3,0,0,3,20,0,120,0,1,1,0.67,72.801787 +Smacks,K,C,110,2,1,70,1,9,15,40,25,2,1,0.75,31.230054 +Special K,K,C,110,6,0,230,1,16,3,55,25,1,1,1,53.131324 +Strawberry Fruit Wheats,N,C,90,2,0,15,3,15,5,90,25,2,1,1,59.363993 +Total Corn Flakes,G,C,110,2,1,200,0,21,3,35,100,3,1,1,38.839746 +Total Raisin Bran,G,C,140,3,1,190,4,15,14,230,100,3,1.5,1,28.592785 +Total Whole Grain,G,C,100,3,1,200,3,16,3,110,100,3,1,1,46.658844 +Triples,G,C,110,2,1,250,0,21,3,60,25,3,1,0.75,39.106174 +Trix,G,C,110,1,1,140,0,13,12,25,25,2,1,1,27.753301 +Wheat Chex,R,C,100,3,1,230,3,17,3,115,25,1,1,0.67,49.787445 +Wheaties,G,C,100,3,1,200,3,17,3,110,25,1,1,1,51.592193 +Wheaties Honey Gold,G,C,110,2,1,200,1,16,8,60,25,1,1,0.75,36.187559 diff --git a/week3/resources/hope.txt b/week3/resources/hope.txt new file mode 100644 index 0000000..c360621 --- /dev/null +++ b/week3/resources/hope.txt @@ -0,0 +1,14 @@ +בַּעֲלַת-הַנוֹצָה הִיא תִּקְוָה +– תִשְׁכֹּן בַּנְּשָׁמָה זוּ +הַמִּלִּים, בְּלִי הַנִּגּוּן אֶת הִיא שָׁרָה +– מִשִּׁיר פּוֹסֶקֶת וְאֵינָהּ + +בְּיוֹתֵר? תִּמְתַּק מָתַי רִנָּתָהּ +הַסּוּפָה תְהִי וְקָשָׁה-מָרָה – תָסְכַּת בִּסְעָרָה עֵת +הַקְּטַנָּה, הַצִּפּוֹר אֶת תַּכְלִים תּוּכַל אֲשֶׁר +חִמֵּמָה. רַבִּים כֹּה זוּ + +– קָרוֹת-מִקֹּר בַּאֲרָצוֹת שְׁמַעְתִּיהָ +– זָרִים-מוּזָרִים יַמִּים וְעַל +בְּעֹצֶם-מְצוּקָה, גַּם אֵלֶּה, וּבְכָל +מִמֶּנִּי. – פֵּרוּר בִּקְּשָׁה לֹא מֵעוֹלָם \ No newline at end of file diff --git a/week3/resources/passwords.txt b/week3/resources/passwords.txt new file mode 100644 index 0000000..1b9df6a --- /dev/null +++ b/week3/resources/passwords.txt @@ -0,0 +1,25 @@ +123456 +password +123456789 +12345678 +12345 +111111 +1234567 +sunshine +qwerty +iloveyou +princess +admin +welcome +666666 +abc123 +football +123123 +monkey +654321 +!@#$%^&* +charlie +aa123456 +donald +password1 +qwerty123 \ No newline at end of file