diff --git a/week4/4_Unpacking.ipynb b/week4/4_Unpacking.ipynb
new file mode 100644
index 0000000..f5ea802
--- /dev/null
+++ b/week4/4_Unpacking.ipynb
@@ -0,0 +1,929 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Unpacking"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## הקדמה"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n", + " הנה שורה שתראה לנו קצת שונה תחבירית מכל מה שהכרנו עד עכשיו:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "country, population = ('Israel', 8712000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " בצד ימין יש tuple שמכיל שני איברים, ואנחנו מבצעים השמה לשני משתנים ששמותיהם country ו־population.
\n",
+ " אמנם לא הייתי נותן לפיסת הקוד הזו את תואר פיסת הקוד הנאה בעולם, אבל נראה שפייתון יודע להריץ אותה:
\n",
+ "
\n",
+ " חזינו כאן במעין השמה כפולה שפייתון מאפשרת לנו לבצע:
\n",
+ " את האיבר הראשון בצד ימין היא הכניסה לאיבר הראשון בצד שמאל, ואת האיבר השני בצד ימין היא הכניסה לאיבר השני בצד שמאל.
\n",
+ "
\n", + " התחביר שמאפשר לפייתון לפרק מבנה ולבצע השמה של האיברים שבו לכמה שמות משתנים במקביל, קיבל את השם unpacking.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unpacking לתוך משתנים" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### המקרה הקלאסי" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " מתכנתים רבים מנצלים את הנוחות שב־unpacking, מה שגורם לו להופיע בקוד שתמצאו \"בעולם האמיתי\" פעמים רבות.
\n",
+ " ניתן לבצע השמה לכמה משתנים שנרצה במקביל:\n",
+ "
\n", + " הטכניקה הזו עובדת גם עבור טיפוסים אחרים שמוגדרים כ־iterable:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a, b = [1, 2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " ואפילו בלי סוגריים (זה לא קסם – בצד ימין נוצר בפועל tuple):\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a, b = 1, 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " או כ\"חילוץ איברים\" מתוך משתנה קיים לתוך כמה משתנים נפרדים:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "point_on_map = (36.672011, 65.807761)\n", + "x, y = point_on_map\n", + "print(f\"The treasure should be in ({x}, {y}).\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " בדוגמה האחרונה יצרנו בשורה הראשונה משתנה שמצביע ל־tuple. ב־tuple ישנם שני מספרים מסוג float.
\n",
+ " בשורה השנייה פירקנו את ה־tuple – הערך הראשון שלו הוכנס לתוך המשתנה x והערך השני שלו הוכנס לתוך המשתנה y. \n",
+ "
\n",
+ " שימוש מקובל מאוד ל־unpacking אותו כבר הספקתם לראות בעבר, מתרחש בלולאות for.
\n",
+ " ניצור רשימה של tuple־ים, בה כל tuple ייצג מדינה ואת כמות האנשים החיים בה:\n",
+ "
\n", + "בעולם ללא unpacking, היינו צריכים לכתוב את הקוד הבא:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for item in countries_with_population:\n", + " country = item[0]\n", + " population = item[1]\n", + " print(f\"There are {population:9,} people in {country}.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " אבל כיוון שאנחנו חיים בעולם טוב יותר, פייתון מאפשרת לנו לעשות את הטריק הבא:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for country, population in countries_with_population:\n", + " print(f\"There are {population:9,} people in {country}.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| 0 | \n", + "1 | \n", + "2 | \n", + "3 | \n", + "||||||||||||||||||||||||
\n",
+ "
| \n",
+ " \n",
+ "
| \n",
+ " \n",
+ "
| \n",
+ " \n",
+ "
| \n",
+ " ||||||||||||||||||||||||
| -4 | \n", + "-3 | \n", + "-2 | \n", + "-1 | \n", + "
\n",
+ " באיור למעלה, התאים האדומים מפורקים לתוך המשתנה country והתאים הירוקים לתוך המשתנה population.
\n",
+ " כל איטרציה של הלולאה תגרום לפירוק של צמד אחד מתוך הרשימה, והשמתם בהתאמה לתוך צמד המשתנים שבראש לולאת ה־for.\n",
+ "
\n",
+ " הרעיון של unpacking הופך להיות שימושי מאוד כשאנחנו רוצים לעבור על המפתח והערך של מילון בו זמנית.
\n",
+ " כל שנצטרך לעשות כדי לקבל את המפתח לצד הערך בכל איטרציה, זה להשתמש בפעולה items על המילון:\n",
+ "
\n",
+ " המקרה הזה לא שונה מהמקרים הקודמים שראינו, אבל חשבתי שיהיה נחמד לראות אותו במפורש.
\n",
+ " הפעם נקח פונקציה שמחזירה tuple, ונשתמש ב־unpacking כדי לפרק את הערכים שהיא מחזירה למשתנים.
\n",
+ "
\n", + " נשתמש בפונקציה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "division_and_modulo(5, 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " והרי שאם מוחזר לנו tuple, אפשר לעשות לו unpacking:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "div, mod = division_and_modulo(5, 2)\n", + "print(f\"division: {div}, modulo: {mod}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unpacking לארגומנטים" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " נבחן את הקוד הפשוט הבא:
\n",
+ "
\n",
+ " הגדרנו פונקציה שמדפיסה לנו יפה מיקומים לפי x ו־y שהיא מקבלת.
\n",
+ " המימוש הגיוני, אבל אוי א בראך! השימוש מאוד לא נוח!
\n",
+ " כל פעם אנחנו צריכים לפרק את ה־tuple שמכיל את המיקום ל־2 איברים, ולשלוח כל אחד מהם בנפרד.\n",
+ "
\n", + " כפתרון למצב, פייתון מאפשרת לנו לעשות את הקסם הנפלא הבא:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def print_treasure_location(x, y):\n", + " print(f\"{x}°N, {y}°E\")\n", + "\n", + "treasure_location = (36.671111, 65.808056)\n", + "print_treasure_location(*treasure_location)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " נראה מוזר? זו לא טעות, זהו באמת תחביר שמעולם לא ראינו עדיין!
\n",
+ " הכוכבית מפרקת את ה־tuple שהגדרנו, treasure_location, ושולחת לארגומנט x את הערך הראשון ולארגומנט y את הערך השני.\n",
+ "
\n", + " אם היו לנו ערכים רבים, היינו יכולים להשתמש באותו טריק בלולאה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "treasure_locations = [\n", + " (36.671111, 65.808056),\n", + " (53.759748, -2.648121),\n", + " (52.333333, 1.183333),\n", + " (52.655278, -1.906667),\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def print_treasure_location(x, y):\n", + " print(f\"{x}°N, {y}°E\")\n", + "\n", + "for treasure_location in treasure_locations:\n", + " print_treasure_location(*treasure_location)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " אבל נזכור שאנחנו יכולים להשתמש גם בתעלול שלמדנו על unpacking בתוך for:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def print_treasure_location(x, y):\n", + " print(f\"{x}°N, {y}°E\")\n", + "\n", + "for treasure_x, treasure_y in treasure_locations:\n", + " print_treasure_location(treasure_x, treasure_y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### unpacking לארגומנטים לפי שם הארגומנט" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " מצוידים בפונקציה להדפסת המיקום, אנחנו מקבלים את רשימת המילונים הבאה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "treasure_maps = [\n", + " {'x': 36.671111, 'y': 65.808056},\n", + " {'x': 53.759748, 'y': -2.648121},\n", + " {'x': 52.333333, 'y': 1.183333},\n", + " {'x': 52.655278, 'y': -1.906667}\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " אין מנוס, דנו אותנו לחיי עבדות של פירוק מילונים ושליחת ערכיהם לפונקציות! 😢\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def print_treasure_location(x, y):\n", + " print(f\"{x}°N, {y}°E\")\n", + "\n", + "for location in treasure_maps:\n", + " print_treasure_location(location.get('x'), location.get('y'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " או שאולי לא?\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " במקרה המאוד מיוחד של מילון, ניתן לשלוח לפונקציה את הפרמטרים בעזרת unpacking עם שתי כוכביות.
\n",
+ " המפתחות של המילון צריכים לציין את שם הפרמטרים של הפונקציה, והערכים במילון יהיו הערך שיועבר לאותם פרמטרים:\n",
+ "
\n",
+ " מה קרה פה?
\n",
+ " באיטרציה הראשונה location היה {'x': 36.671111, 'y': 65.808056}.
\n",
+ " הפונקציה print_treasure_locations מחכה שיעבירו לה ערך לפרמטר x ולפרמטר y.
\n",
+ " ה־unpacking שעשינו בעזרת שתי הכוכביות העביר את הערך של המפתח 'x' במילון לפרמטר x, ואת הערך שהיה תחת המפתח 'y' במילון לפרמטר y.\n",
+ "
\n", + " נראה דוגמה נוספת לפונקציה שמקבלת שנה, חודש ויום ומחזירה לנו תאריך כמחרוזת:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def stringify_date(year, month, day):\n", + " return f'{year}-{month}-{day}'\n", + "\n", + "date = {'year': 1815, 'month': 12, 'day': 10}\n", + "print(stringify_date(**date))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## שגיאות" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " אנחנו רגילים שפייתון די מתירני, אבל על unpacking תקין הוא לא מוותר.
\n",
+ " בדוגמה הבאה אנחנו מנסים לחלץ שני איברים לתוך שלושה משתנים, וזה לא נגמר טוב:\n",
+ "
\n", + " נקבל שגיאה דומה אך שונה כשננסה לחלץ מספר לא נכון של ארגומנטים לתוך פונקציה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def print_treasure_location(x, y):\n", + " print(f\"{x}°N, {y}°E\")\n", + "\n", + "location_3d = (36.671111, 65.808056, 63.124592)\n", + "print_treasure_location(*location_3d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " אם ננסה לעשות unpacking לאיבר שאינו iterable, תתקבל השגיאה הבאה:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a, b = 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## קוד לדוגמה" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ "סדרת פיבונאצ'י היא סדרה שמתחילה באיברים 1 ו־1, וכל איבר בה הוא סכום שני האיברים הקודמים לו.
\n",
+ "האיברים הראשונים בסדרה, הם (מימין לשמאל) 1, 1, 2, 3, 5, 8, וכך הסדרה ממשיכה.
\n",
+ "במימוש פונקציה שמקבלת מספר ומחזירה את סכום כל איברי הסדרה עד אותו מספר, נוכל להשתמש ב־unpacking כדי לשפר את הקריאות של הפונקציה:\n",
+ "
\n",
+ " לפניכם tuple המכיל מספר מילונים, כאשר כל מילון מייצג דמות חשודה ברצח.
\n",
+ " בתוך כל אחד מהמילונים, תחת המפתח evidences, ישנו tuple שבו שני איברים.
\n",
+ " האיבר הראשון הוא הנשק שנתפס על ידי המשטרה, והאיבר השני הוא המיקום המרכזי בו הדמות הייתה באותו יום.
\n",
+ " בהנתן שהרצח בוצע על ידי אקדח דרינגר (derringer) ב־Petersen House, הדפיסו רק את שמות האנשים שעדיין חשודים ברצח.
\n",
+ " השתדלו להשתמש ב־unpacking לפחות פעמיים.\n",
+ "
\n", + " לנוחיותכם, הנה פונקציה שמקבלת כלי נשק ומיקום, ובודקת האם הראיות תואמות:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 189, + "metadata": {}, + "outputs": [], + "source": [ + "def check_evidences(weapon, location):\n", + " return weapon.lower() == 'derringer' and location.lower() == 'petersen house'" + ] + } + ], + "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.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/week4/6_Builtins.ipynb b/week4/5_Builtins.ipynb similarity index 96% rename from week4/6_Builtins.ipynb rename to week4/5_Builtins.ipynb index 99e608a..50a2c1d 100644 --- a/week4/6_Builtins.ipynb +++ b/week4/5_Builtins.ipynb @@ -1790,6 +1790,77 @@ " print(f\"The sum until {number} is {current_sum}\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ממוצע ציונים" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n",
+ " קבלו רשימת תלמידים, ואז עבור כל תלמיד את רשימת הציונים שלו.
\n",
+ " הדפיסו את התלמיד שממוצע הציונים שלו היה הגבוה ביותר לצד הציונים שלו.\n",
+ "
\n",
" מצאו את עשר המילים הנפוצות ביותר בספר \"מלחמה ושלום\", והדפיסו אותן למסך מהמילה הנפוצה ביותר למילה הכי פחות נפוצה.
\n",
+ " ליד כל מילה הדפיסו את כמות הפעמים שהופיע בספר.
\n",
" הספר נמצא בקובץ war-and-peace.txt בתוך התיקייה resources.\n",
"