user1 = {
    'first_name': 'Christine',
    'last_name': 'Daaé',
    'nickname': 'Little Lotte',
    'age': 20,
}
user2 = {
    'first_name': 'Elphaba',
    'last_name': 'Thropp',
    'nickname': 'Elphie',
    'age': 19,
}

"""
Explanation: <img src="images/logo.jpg" style="display: block; margin-left: auto; margin-right: auto;" alt="לוגו של מיזם לימוד הפייתון. נחש מצויר בצבעי צהוב וכחול, הנע בין האותיות של שם הקורס: לומדים פייתון. הסלוגן המופיע מעל לשם הקורס הוא מיזם חינמי ללימוד תכנות בעברית.">
<span style="text-align: right; direction: rtl; float: right;">מחלקות</span>
<span style="text-align: right; direction: rtl; float: right; clear: both;">הקדמה</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    בוקר חדש, השמש הפציעה והחלטתם שצברתם מספיק ידע בקורס כדי לפתוח רשת חברתית משלכם, בשם צ'יקצ'וק.<br>
    אתם משליכים את מחברות הפייתון מהחלון ומתחילים לתכנת במרץ את המערכת שתעזור לכם לנהל את המשתמשים.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    לכל משתמש יש את התכונות הבאות:
</p>

<ul style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>שם פרטי</li>
    <li>שם משפחה</li>
    <li>כינוי</li>
    <li>גיל</li>
</ul>

<div class="align-center" style="display: flex; text-align: right; direction: rtl; clear: both;">
    <div style="display: flex; width: 10%; float: right; clear: both;">
        <img src="images/exercise.svg" style="height: 50px !important;" alt="תרגול"> 
    </div>
    <div style="width: 70%">
        <p style="text-align: right; direction: rtl; float: right; clear: both;">
            בחרו סוג משתנה שיאפשר לכם לאחסן בנוחות את הנתונים הללו.<br>
            צרו שני משתמשים לדוגמה, והשתמשו בסוג המשתנה שבחרתם.
        </p>
    </div>
    <div style="display: flex; width: 20%; border-right: 0.1rem solid #A5A5A5; padding: 1rem 2rem;">
        <p style="text-align: center; direction: rtl; justify-content: center; align-items: center; clear: both;">
            <strong>חשוב!</strong><br>
            פתרו לפני שתמשיכו!
        </p>
    </div>
</div>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    לפני שנציג את פתרון השאלה, נעמיק מעט ברעיון הכללי שעומד מאחורי הדוגמה הזו.<br>
    <mark>כל משתמש שניצור הוא מעין אסופת תכונות</mark> – במקרה שלנו התכונות הן שם פרטי, שם משפחה, כינוי וגיל.<br>
    לכל תכונה יהיה ערך המתאים לה, ויחד הערכים הללו יצרו משתמש אחד.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נמצא עוד דוגמאות לאסופות תכונות שכאלו:
</p>

<ul style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>תכונותיו של שולחן הן גובה, מספר רגליים, צבע, אורך ורוחב.</li>
    <li>תכונותיה של נורה הן צבע ומצב (דולקת או כבויה).</li>
    <li>תכונותיו של תרגיל בקורס הן השבוע והמחברת שבהן הוא הופיע, כותרת והוראות התרגיל.</li>
    <li>תכונותיו של שיר הן מילות השיר, האומנים שהשתתפו ביצירתו ואורכו.</li>
</ul>

<div class="align-center" style="display: flex; text-align: right; direction: rtl; clear: both;">
    <div style="display: flex; width: 10%; float: right; clear: both;">
        <img src="images/exercise.svg" style="height: 50px !important;" alt="תרגול"> 
    </div>
    <div style="width: 70%">
        <p style="text-align: right; direction: rtl; float: right; clear: both;">
            חשבו על עוד 3 דוגמאות לעצמים שאפשר לתאר כערכים עם אסופת תכונות.
        </p>
    </div>
    <div style="display: flex; width: 20%; border-right: 0.1rem solid #A5A5A5; padding: 1rem 2rem;">
        <p style="text-align: center; direction: rtl; justify-content: center; align-items: center; clear: both;">
            <strong>חשוב!</strong><br>
            פתרו לפני שתמשיכו!
        </p>
    </div>
</div>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    ניצור שני משתמשים לדוגמה לפי תכונותיהם שהוצגו לעיל:
</p>
End of explanation
"""


def create_user(first_name, last_name, nickname, current_age):
    return {
        'first_name': first_name,
        'last_name': last_name,
        'nickname': nickname,
        'age': current_age,
    }


# נקרא לפונקציה כדי לראות שהכל עובד כמצופה
new_user = create_user('Bayta', 'Darell', 'Bay', 24)
print(new_user)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    תוכלו ליצור בעצמכם פונקציה שיוצרת משתמש חדש?<br>
    זה לא מסובך מדי:
</p>
End of explanation
"""


def describe_as_a_string(user):
    first_name = user['first_name']
    last_name = user['last_name']
    full_name = f'{first_name} {last_name}'
    nickname = user['nickname']
    age = user['age']
    return f'{nickname} ({full_name}) is {age} years old.'


def celebrate_birthday(user):
    user['age'] = user['age'] + 1


print(describe_as_a_string(new_user))
celebrate_birthday(new_user)
print("--- After birthday")
print(describe_as_a_string(new_user))

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    <mark>נוכל גם לממש פונקציות שיעזרו לנו לבצע פעולות על כל אחד מהמשתמשים.</mark><br>
    לדוגמה: הפונקציה <var>describe_as_a_string</var> תקבל משתמש ותחזיר לנו מחרוזת שמתארת אותו,<br>
    והפונקציה <var>celeberate_birthday</var> תקבל משתמש ותגדיל את גילו ב־1:
</p>
End of explanation
"""


class User:
    pass

"""
Explanation: <div class="align-center" style="display: flex; text-align: right; direction: rtl;">
    <div style="display: flex; width: 10%; float: right; ">
        <img src="images/recall.svg" style="height: 50px !important;" alt="תזכורת" title="תזכורת"> 
    </div>
    <div style="width: 90%">
        <p style="text-align: right; direction: rtl;">
            הצלחנו לערוך את ערכו של <code>user['age']</code> מבלי להחזיר ערך, כיוון שמילונים הם mutable.<br>
            אם זה נראה לכם מוזר, חזרו למחברת על mutability ו־immutability.
        </p>
    </div>
</div>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    בשלב הזה בתוכניתנו קיימות קבוצת פונקציות שמטרתן היא ניהול של משתמשים ושל תכונותיהם.<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נוכל להוסיף למשתמש תכונות נוספות, כמו דוא"ל ומשקל, לדוגמה,<br>
    או להוסיף לו פעולות שיהיה אפשר לבצע עליו, כמו הפעולה <var>eat_bourekas</var>, שמוסיפה לתכונת המשקל של המשתמש חצי קילו.<br>
</p>

<span style="text-align: right; direction: rtl; float: right; clear: both;">חסרונות</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    אף על פי שהרעיון נחמד, ככל שנרבה להוסיף פעולות ותכונות, תגבר תחושת האי־סדר שאופפת את הקוד הזה.<br>
    קל לראות שהקוד שכתבנו מפוזר על פני פונקציות רבות בצורה לא מאורגנת.<br>
    במילים אחרות – אין אף מבנה בקוד שתחתיו מאוגדות כל הפונקציות והתכונות ששייכות לטיפול במשתמש.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    הבעיה תצוף כשנרצה להוסיף לתוכנה שלנו עוד מבנים שכאלו.<br>
    לדוגמה, כשנרצה להוסיף לצ'יקצ'וק יכולת לניהול סרטונים – שתכונותיהם אורך סרטון ומספר לייקים, והפעולה עליהם היא היכולת לעשות Like לסרטון.<br>
    הקוד לניהול המשתמש והקוד לניהול הסרטונים עלולים להתערבב, יווצרו תלויות ביניהם וחוויית ההתמצאות בקוד תהפוך ללא נעימה בעליל.<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    החוסר באיגוד התכונות והפונקציות אף מקשה על הקורא להבין לאן שייכות כל אחת מהתכונות והפונקציות, ומה תפקידן בקוד.<br>
    מי שמסתכל על הקוד שלנו לא יכול להבין מייד ש־<var>describe_as_a_string</var> מיועדת לפעול רק על מבנים שנוצרו מ־<var>create_user</var>.<br>
    הוא עלול לנסות להכניס מבנים אחרים ולהקריס את התוכנית, או גרוע מכך – להיתקל בבאגים בעתיד, בעקבות שימוש לא נכון בפונקציה.
</p>

<span style="text-align: right; direction: rtl; float: right; clear: both;">הגדרה</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    במהלך המחברת ראינו דוגמאות למבנים שהגדרנו <mark>כאוספים של תכונות ושל פעולות</mark>.<br>
    משתמש באפליקציית צ'יקצ'וק, לדוגמה, מורכב מהתכונות שם פרטי, שם משפחה, כינוי וגיל, ומהפעולות "חגוג יום הולדת" ו"תאר כמחרוזת".<br>
    נורה עשויה להיות מורכבת מהתכונות צבע ומצב (דולקת או לא), ומהפעולות "הדלק נורה" ו"כבה נורה".<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    <dfn>מחלקה</dfn> היא דרך לתאר לפייתון אוסף כזה של תכונות ושל פעולות, ולאגד אותן תחת מבנה אחד.<br>
    אחרי שתיארנו בעזרת מחלקה אילו תכונות ופעולות מאפיינות עצם מסוים, נוכל להשתמש בה כדי לייצר כמה עצמים כאלו שנרצה.<br> 
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נדמיין מחלקה כמו שבלונה – <mark>תבנית</mark> שמתארת אילו תכונות ופעולות מאפיינות סוג עצם מסוים.<br>
    מחלקה שעוסקת במשתמשים, לדוגמה, תתאר עבור פייתון מאילו תכונות ופעולות מורכב כל משתמש.<br>
</p>

<figure>
    <img src="images/user_class.svg?v=1" style="max-width: 650px; margin-right: auto; margin-left: auto; text-align: center;" alt="במרכז התמונה ניצבת צללית של אדם (משתמש). בצד ימין שלו יש תיבה עם הכותרת 'תכונות', ובתוכה המילים 'שם פרטי', 'שם משפחה', 'כינוי' ו'גיל'. בצד שמאל שלו יש תיבה נוספת הנושאת את הכותרת 'פעולות', ובתוכה המילים 'חגוג יום הולדת' ו'תאר משתמש'."/>
    <figcaption style="margin-top: 2rem; text-align: center; direction: rtl;">איור המתאר את התכונות ואת הפעולות השייכות למחלקה "משתמש".</figcaption>
</figure>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    בעזרת אותה מחלקת משתמשים (או שבלונת משתמשים, אם תרצו), נוכל ליצור משתמשים רבים.<br>
    כל משתמש שניצור באמצעות השבלונה ייקרא "<dfn>מופע</dfn>" (או <dfn>Instance</dfn>) – יחידה אחת, עצמאית, שמכילה את התכונות והפעולות שתיארנו.<br>
    אנחנו נשתמש במחלקה שוב ושוב כדי ליצור כמה משתמשים שנרצה, בדיוק כמו שנשתמש בשבלונה.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    יש עוד הרבה מה להגיד והרבה מה להגדיר, אבל נשמע שמתחתי אתכם מספיק.<br>
    בואו ניגש לקוד!
</p>

<span style="text-align: right; direction: rtl; float: right; clear: both;">יצירת מחלקות</span>
<span style="text-align: right; direction: rtl; float: right; clear: both;">מחלקה בסיסית</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    ראשית, ניצור את המחלקה הפשוטה ביותר שאנחנו יכולים לבנות, ונקרא לה <var>User</var>.<br>
    בהמשך המחברת נרחיב את המחלקה, והיא תהיה זו שמטפלת בכל הקשור במשתמשים של צ'יקצ'וק:
</p>
End of explanation
"""


user1 = User()

"""
Explanation: <div class="align-center" style="display: flex; text-align: right; direction: rtl;">
    <div style="display: flex; width: 10%; float: right; ">
        <img src="images/recall.svg" style="height: 50px !important;" alt="תזכורת" title="תזכורת"> 
    </div>
    <div style="width: 90%">
        <p style="text-align: right; direction: rtl;">
            ניסינו ליצור את המבנה הכי קצר שאפשר, אבל <code>class</code> חייב להכיל קוד.<br>
            כדי לעקוף את המגבלה הזו, השתמשנו במילת המפתח <code>pass</code>, שאומרת לפייתון "אל תעשי כלום".
        </p>
    </div>
</div>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    בקוד שלמעלה השתמשנו במילת המפתח <code>class</code> כדי להצהיר על מחלקה חדשה.<br>
    מייד לאחר מכן ציינו את שם המחלקה שאנחנו רוצים ליצור – <var>User</var> במקרה שלנו.<br>
    שם המחלקה נתון לחלוטין לבחירתנו, והמילה <var>User</var> לא אומרת לפייתון שום דבר מיוחד. באותה המידה יכולנו לבחור כל שם אחר.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    הדבר שחשוב לזכור הוא שהמחלקה היא <em>לא</em> המשתמש עצמו, אלא רק השבלונה שלפיה פייתון תבנה את המשתמש.<br>
    אמנם כרגע המחלקה <var>User</var> ריקה ולא מתארת כלום, אבל פייתון עדיין תדע ליצור משתמש חדש אם נבקש ממנה לעשות זאת.<br>
    נבקש מהמחלקה ליצור עבורנו משתמש חדש. נקרא לה בשמה ונוסיף סוגריים, בדומה לקריאה לפונקציה:
</p>
End of explanation
"""


user1.first_name = "Miles"
user1.last_name = "Prower"
user1.age = 8
user1.nickname = "Tails"

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    כעת יצרנו משתמש, ואנחנו יכולים לשנות את התכונות שלו.<br>
    מבחינה מילולית, נהוג להגיד שיצרנו <dfn>מופע</dfn> (<dfn>Instance</dfn>) או <dfn>עצם</dfn> (אובייקט, <dfn>Object</dfn>) מסוג <var>User</var>, ששמו <var>user1</var>.<br>
    השתמשנו לשם כך ב<dfn>מחלקה</dfn> בשם <var>User</var>.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נשנה את תכונות המשתמש.<br>
    כדי להתייחס לתכונה של מופע כלשהו בפייתון, נכתוב את שם המשתנה שמצביע למופע, נקודה, ואז שם התכונה.<br>
    אם נרצה לשנות את התכונה – נבצע אליה השמה:
</p>
End of explanation
"""


print(user1.age)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    נוכל לאחזר את התכונות הללו בקלות, באותה הצורה:
</p>
End of explanation
"""


type(user1)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    ואם נבדוק מה הסוג של המשתנה <var>user1</var>, מצפה לנו הפתעה נחמדה:
</p>
End of explanation
"""


user2 = User()
user2.first_name = "Harry"
user2.last_name = "Potter"
user2.age = 39
user2.nickname = "BoyWhoLived1980"

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    איזה יופי! המחלקה גרמה לכך ש־<var>User</var> הוא ממש סוג משתנה בפייתון עכשיו.<br>
    קחו לעצמכם רגע להתפעל – יצרנו סוג משתנה חדש בפייתון!<br>
    אם כך, המשתנה <var>user1</var> מצביע על מופע של משתמש, שסוגו <var>User</var>.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    ננסה ליצור מופע נוסף, הפעם של משתמש אחר:
</p>
End of explanation
"""


print(f"{user1.first_name} {user1.last_name} is {user1.age} years old.")
print(f"{user2.first_name} {user2.last_name} is {user2.age} years old.")

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    ונשים לב ששני המופעים מתקיימים זה לצד זה, ולא דורסים את הערכים זה של זה:
</p>
End of explanation
"""


def describe_as_a_string(user):
    full_name = f'{user.first_name} {user.last_name}'
    return f'{user.nickname} ({full_name}) is {user.age} years old.'


print(describe_as_a_string(user2))

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    המצב הזה מתקיים כיוון שכל קריאה למחלקה <var>User</var> יוצרת מופע חדש של משתמש.<br>
    כל אחד מהמופעים הוא ישות נפרדת שמתקיימת בזכות עצמה.
</p>

<div class="align-center" style="display: flex; text-align: right; direction: rtl; clear: both;">
    <div style="display: flex; width: 10%; float: right; clear: both;">
        <img src="images/exercise.svg" style="height: 50px !important;" alt="תרגול"> 
    </div>
    <div style="width: 70%">
        <p style="text-align: right; direction: rtl; float: right; clear: both;">
            צרו מחלקה בשם <var>Point</var> שמייצגת נקודה.<br>
            צרו 2 מופעים של נקודות: אחת בעלת <var>x</var> שערכו 3 ו־<var>y</var> שערכו 1, והשנייה בעלת <var>x</var> שערכו 4 ו־<var>y</var> שערכו 1.
        </p>
    </div>
    <div style="display: flex; width: 20%; border-right: 0.1rem solid #A5A5A5; padding: 1rem 2rem;">
        <p style="text-align: center; direction: rtl; justify-content: center; align-items: center; clear: both;">
            <strong>חשוב!</strong><br>
            פתרו לפני שתמשיכו!
        </p>
    </div>
</div>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    שמות מחלקה ייכתבו באות גדולה בתחילתם, כדי להבדילם מפונקציות וממשתנים רגילים.<br>
    אם שם המחלקה מורכב מכמה מילים, האות הראשונה בכל מילה תהא אות גדולה. בשם לא יופיעו קווים תחתונים.<br>
    לדוגמה, מחלקת <var>PopSong</var>.
</p>

<span style="text-align: right; direction: rtl; float: right; clear: both;">מחלקה עם פעולות</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    יצירת מחלקה ריקה זה נחמד, אבל זה לא מרגיש שעשינו צעד מספיק משמעותי כדי לשפר את איכות הקוד מתחילת המחברת.<br>
    לדוגמה, אם אנחנו רוצים להדפיס את הפרטים של משתמש מסוים, עדיין נצטרך לכתוב פונקציה כזו:
</p>
End of explanation
"""


class User:
    def describe_as_a_string(user):
        full_name = f'{user.first_name} {user.last_name}'
        return f'{user.nickname} ({full_name}) is {user.age} years old.'


user3 = User()
user3.first_name = "Anthony John"
user3.last_name = "Soprano"
user3.age = 61
user3.nickname = "Tony"

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    הפונקציה עדיין מסתובבת לה חופשייה ולא מאוגדת תחת אף מבנה – וזה בדיוק המצב שניסינו למנוע.<br>
    למזלנו הפתרון לבעיית איגוד הקוד הוא פשוט. נוכל להדביק את קוד הפונקציה תחת המחלקה <code>User</code>:
</p>
End of explanation
"""


user3.describe_as_a_string()

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    בתא שלמעלה הגדרנו את הפונקציה <var>describe_as_a_string</var> בתוך המחלקה <var>User</var>.<br>
    פונקציה שמוגדרת בתוך מחלקה נקראת <dfn>פעולה</dfn> (<dfn>Method</dfn>), שם שניתן לה כדי לבדל אותה מילולית מפונקציה רגילה.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    למעשה, בתא שלמעלה הוספנו את הפעולה <var>describe_as_a_string</var> לשבלונה של המשתמש.<br>
    מעכשיו, כל מופע חדש של משתמש יוכל לקרוא לפעולה <var>describe_as_a_string</var> בצורה הבאה:
</p>
End of explanation
"""


class User:
    def describe_as_a_string(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'


user3 = User()
user3.first_name = "Anthony John"
user3.last_name = "Soprano"
user3.age = 61
user3.nickname = "Tony"
user3.describe_as_a_string()

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    חדי העין שמו ודאי לב למשהו מעט משונה בקריאה לפעולה <var>describe_as_a_string</var>.<br>
    הפעולה מצפה לקבל פרמטר (קראנו לו <var>user</var>), אבל כשקראנו לה בתא האחרון לא העברנו לה אף ארגומנט!<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    זהו קסם ידוע ונחמד של מחלקות: כשמופע קורא לפעולה כלשהי – אותו מופע עצמו מועבר אוטומטית כארגומנט הראשון לפעולה.<br>
    לדוגמה, בקריאה <code dir="ltr">user3.describe_as_a_string()</code>, המופע <var>user3</var> הועבר לתוך הפרמטר <var>user</var> של <var>describe_as_a_string</var>.<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    המוסכמה היא לקרוא תמיד לפרמטר הקסום הזה, זה שהולך לקבל את המופע, בשם <var>self</var>.<br>
    נשנה את ההגדרה שלנו בהתאם למוסכמה:
</p>
End of explanation
"""


def create_user(first_name, last_name, nickname, current_age):
    user = User()
    user.first_name = first_name
    user.last_name = last_name
    user.nickname = nickname
    user.age = current_age
    return user


user4 = create_user('Daenerys', 'Targaryen', 'Mhysa', 23)
print(f"{user4.first_name} {user4.last_name} is {user4.age} years old.")

"""
Explanation: <div class="align-center" style="display: flex; text-align: right; direction: rtl;">
    <div style="display: flex; width: 10%; float: right; ">
        <img src="images/warning.png" style="height: 50px !important;" alt="אזהרה!"> 
    </div>
    <div style="width: 90%">
        <p style="text-align: right; direction: rtl;">
            טעות נפוצה היא לשכוח לשים <var>self</var> כפרמטר הראשון בפעולות שנגדיר.
        </p>
    </div>
</div>

<div class="align-center" style="display: flex; text-align: right; direction: rtl; clear: both;">
    <div style="display: flex; width: 10%; float: right; clear: both;">
        <img src="images/exercise.svg" style="height: 50px !important;" alt="תרגול"> 
    </div>
    <div style="width: 70%">
        <p style="text-align: right; direction: rtl; float: right; clear: both;">
            צרו פעולה בשם <var>describe_as_a_string</var> עבור מחלקת <var>Point</var> שיצרתם.<br>
            הפעולה תחזיר מחרוזת בצורת <samp dir="ltr">(x, y)</samp>.
        </p>
    </div>
    <div style="display: flex; width: 20%; border-right: 0.1rem solid #A5A5A5; padding: 1rem 2rem;">
        <p style="text-align: center; direction: rtl; justify-content: center; align-items: center; clear: both;">
            <strong>חשוב!</strong><br>
            פתרו לפני שתמשיכו!
        </p>
    </div>
</div>

<span style="text-align: right; direction: rtl; float: right; clear: both;">יצירת מופע</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    הפיסה החסרה בפאזל היא יצירת המופע.<br>
    אם נרצה ליצור משתמש חדש, עדיין נצטרך להציב בו תכונות אחת־אחת – וזה לא כזה כיף.<br>
    נשדרג את עצמנו ונכתוב פונקציה שקוראת ל־<var>User</var> ויוצרת מופע עם כל התכונות שלו:<br>
</p>
End of explanation
"""


class User:
    def describe_as_a_string(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'

    def create_user(self, first_name, last_name, nickname, current_age):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = nickname
        self.age = current_age

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    אבל הגדרה שכזו, כמו שכבר אמרנו, סותרת את כל הרעיון של מחלקות.<br>
    הרי המטרה של מחלקות היא קיבוץ כל מה שקשור בניהול התכונות והפעולות תחת המחלקה.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
     נעתיק את <var>create_user</var> לתוך מחלקת <var>User</var>, בשינויים קלים:    
</p>
<ol style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>לא נשכח לשים את <var>self</var> כפרמטר ראשון בחתימת הפעולה.</li>
    <li>כפי שראינו, פעולות במחלקה מקבלות מופע ועובדות ישירות עליו, ולכן נשמיט את השורות <code dir="ltr">user = User()</code> ו־<code dir="ltr">return user</code>.</li>
</ol>
End of explanation
"""


user4 = User()
user4.create_user('Daenerys', 'Targaryen', 'Mhysa', 23)
user4.describe_as_a_string()

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    עכשיו נוכל ליצור משתמש חדש, בצורה החביבה והמקוצרת הבאה:
</p>
End of explanation
"""


current_location = Point()
current_location.create_point(5, 3)
if current_location.distance() == 8:
    print("Success!")

"""
Explanation: <span style="text-align: right; direction: rtl; float: right; clear: both;">תרגיל ביניים: מחלקת נקודות</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    מינרווה מקגונגל יצאה לבילוי לילי בסמטת דיאגון,<br>
    ואחרי לילה עמוס בשתיית שיכר בקלחת הרותחת, היא מעט מתקשה לחזור להוגוורטס.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    הוסיפו את הפעולות <var>create_point</var> ו־<var>distance</var> למחלקת הנקודה שיצרתם.<br>
    הפעולה <var>create_point</var> תקבל כפרמטרים <var>x</var> ו־<var>y</var>, ותיצוק תוכן למופע שיצרתם.<br>
    הפעולה <var>distance</var> תחזיר את המרחק של מקגונגל מהוגוורטס, הממוקם בנקודה <span dir="ltr">(0, 0)</span>.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נוסחת המרחק היא חיבור בין הערכים המוחלטים של נקודות ה־<var>x</var> וה־<var>y</var>.<br>
    לדוגמה:
</p>

<ul style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>המרחק מהנקודה <pre dir="ltr" style="display: inline; margin: 0 0.5em;">x = 5, y = 3</pre> הוא <samp>8</samp>.</li>
    <li>המרחק מהנקודה <pre dir="ltr" style="display: inline; margin: 0 0.5em;">x = 0, y = 3</pre> הוא <samp>3</samp>.</li>
    <li>המרחק מהנקודה <pre dir="ltr" style="display: inline; margin: 0 0.5em;">x = -3, y = 3</pre> הוא <samp>6</samp>.</li>
    <li>המרחק מהנקודה <pre dir="ltr" style="display: inline; margin: 0 0.5em;">x = -5, y = 0</pre> הוא <samp>5</samp>.</li>
    <li>המרחק מהנקודה <pre dir="ltr" style="display: inline; margin: 0 0.5em;">x = 0, y = 0</pre> הוא <samp>0</samp>.</li>
</ul>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    ודאו שהתוכנית שלכם מחזירה <samp dir="ltr">Success!</samp> עבור הקוד הבא:
</p>
End of explanation
"""


user4 = User()
user4.create_user('Daenerys', 'Targaryen', 'Mhysa', 23)
str(user4)

"""
Explanation: <span style="text-align: right; direction: rtl; float: right; clear: both;">פעולות קסם</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    כדי להקל אפילו עוד יותר על המלאכה, בפייתון יש <dfn>פעולות קסם</dfn> (<dfn>Magic Methods</dfn>).<br>
    אלו פעולות עם שם מיוחד, שאם נגדיר אותן במחלקה, הן ישנו את ההתנהגות שלה או של המופעים הנוצרים בעזרתה.
</p>

<h4 style="text-align: right; direction: rtl; float: right; clear: both;">הפעולה <code>__str__</code></h4>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נתחיל, לדוגמה, מהיכרות קצרה עם פעולת הקסם <code>__str__</code> (עם קו תחתון כפול, מימין ומשמאל לשם הפעולה).<br>
    אם ננסה סתם ככה להמיר למחרוזת את <var>user4</var> שיצרנו קודם לכן, נקבל בהלה והיסטריה:
End of explanation
"""


print(user4)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    פייתון אמנם אומרת דברים נכונים, כמו שמדובר באובייקט (מופע) מהמחלקה <var>User</var> ואת הכתובת שלו בזיכרון, אבל זה לא באמת מועיל.<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    כיוון שפונקציית ההדפסה <var>print</var>, מאחורי הקלעים, מבקשת את צורת המחרוזת של הארגומנט שמועבר אליה,<br>
    גם קריאה ל־<var>print</var> ישירות על <var>user4</var> תיצור את אותה תוצאה לא ססגונית:
</p>
End of explanation
"""


print(user4.describe_as_a_string())

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    המחלקה שלנו, כמובן, כבר ערוכה להתמודד עם המצב.<br>
    בזכות הפעולה <var>describe_as_a_string</var> שהגדרנו קודם לכן נוכל להדפיס את פרטי המשתמש בקלות יחסית:
</p>
End of explanation
"""


class User:
    def __str__(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'

    def create_user(self, first_name, last_name, nickname, current_age):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = nickname
        self.age = current_age


user5 = User()
user5.create_user('James', 'McNulty', 'Jimmy', 49)
print(user5)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    אבל יש דרך קלה עוד יותר!<br>
    ניחשתם נכון – פעולת הקסם <code>__str__</code>.<br>
    נחליף את השם של הפעולה <var>describe_as_a_string</var>, ל־<code>__str__</code>:
</p>
End of explanation
"""


class User:
    def __init__(self):
        print("New user has been created!")

    def __str__(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'

    def create_user(self, first_name, last_name, nickname, current_age):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = nickname
        self.age = current_age


user5 = User()
user5.create_user('Lorne', 'Malvo', 'Mick', 23)
print(user5)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    ראו איזה קסם! עכשיו המרה של כל מופע מסוג <var>User</var> למחרוזת היא פעולה ממש פשוטה!<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    בתא שלמעלה, הגדרנו את פעולת הקסם <code>__str__</code>.<br>
    הפעולה מקבלת כפרמטר את <var>self</var>, המופע שביקשנו להמיר למחרוזת,<br>
    ומחזירה לנו מחרוזת שאנחנו הגדרנו כמחרוזת שמתארת את המופע.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    הגדרת פעולת הקסם <code>__str__</code> עבור מחלקה מסוימת מאפשרת לנו להמיר מופעים למחרוזות בצורה טבעית.
</p>

<h4 style="text-align: right; direction: rtl; float: right; clear: both;">הפעולה <code>__init__</code></h4>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    פעולת קסם חשובה אף יותר, ואולי המפורסמת ביותר, נקראת <code>__init__</code>.<br>
    היא מאפשרת לנו להגדיר מה יקרה ברגע שניצור מופע חדש:
</p>
End of explanation
"""


class User:
    def __init__(self, message):
        self.creation_message = message
        print(self.creation_message)

    def __str__(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'

    def create_user(self, first_name, last_name, nickname, current_age):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = nickname
        self.age = current_age


user5 = User("New user has been created!")  # תראו איזה מגניב
user5.create_user('Lorne', 'Malvo', 'Mick', 58)
print(user5)
print(f"We still have the message: {user5.creation_message}")

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    בדוגמת הקוד שלמעלה הגדרנו את פעולת הקסם <code>__init__</code>, שתרוץ מייד כשנוצר מופע חדש.<br>
    החלטנו שברגע שייווצר מופע של משתמש, תודפס ההודעה <samp dir="ltr">New user has been created!</samp>.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    הכיף הגדול ב־<code>__init__</code> הוא היכולת שלה לקבל פרמטרים.<br>
    נוכל להעביר אליה את הארגומנטים בקריאה לשם המחלקה, בעת יצירת המופע 🤯
</p>
End of explanation
"""


class User:
    def __init__(self, first_name, last_name, nickname, current_age):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = nickname
        self.age = current_age
        print("Yayy! We have just created a new instance! :D")

    def __str__(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'


user5 = User('Lorne', 'Malvo', 'Mick', 58)
print(user5)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    בתא שלמעלה הגדרנו שפעולת הקסם <code>__init__</code> תקבל כפרמטר הודעה להדפסה.<br>
    ההודעה תישמר בתכונה <var>creation_message</var> השייכת למופע, ותודפס מייד לאחר מכן.<br>
    את ההודעה העברנו כארגומנט בעת הקריאה לשם המחלקה, <var>User</var>, שיוצרת את המופע.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    ואם כבר יש לנו משהו שרץ כשאנחנו יוצרים את המופע... והוא יודע לקבל פרמטרים...<br>
    אתם חושבים על מה שאני חושב?<br>
    בואו נשנה את השם של <var>create_user</var> ל־<code>__init__</code>!<br>
    בצורה הזו נוכל לצקת את התכונות למופע מייד עם יצירתו, ולוותר על קריאה נפרדת לפעולה שמטרתה למלא את הערכים:
</p>
End of explanation
"""


snailchat_users = [
    ['Mike', 'Shugarberg', 'Marker', 36],
    ['Hammer', 'Doorsoy', 'Tzweetz', 43],
    ['Evan', 'Spygirl', 'Odd', 30],
]

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    איגדנו את יצירת תכונות המופע תחת פעולה אחת, שרצה כשהוא נוצר.<br>
    הרעיון הנפלא הזה נפוץ מאוד בשפות תכנות שתומכות במחלקות, ומוכרת בשם <dfn>פעולת אתחול</dfn> (<dfn>Initialization Method</dfn>).<br>
    זו גם הסיבה לשם הפעולה – המילה init נגזרת מהמילה initialization, אתחול. 
</p>

<div class="align-center" style="display: flex; text-align: right; direction: rtl; clear: both;">
    <div style="display: flex; width: 10%; float: right; clear: both;">
        <img src="images/exercise.svg" style="height: 50px !important;" alt="תרגול"> 
    </div>
    <div style="width: 70%">
        <p style="text-align: right; direction: rtl; float: right; clear: both;">
            שפצו את מחלקת הנקודה שיצרתם, כך שתכיל <code>__init__</code> ו־<code>__str__</code>.
        </p>
    </div>
    <div style="display: flex; width: 20%; border-right: 0.1rem solid #A5A5A5; padding: 1rem 2rem;">
        <p style="text-align: center; direction: rtl; justify-content: center; align-items: center; clear: both;">
            <strong>חשוב!</strong><br>
            פתרו לפני שתמשיכו!
        </p>
    </div>
</div>

<span style="text-align: right; direction: rtl; float: right; clear: both;">ייצור מסחרי</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    צ'יקצ'וק שמה את ידה על פרטי המשתמשים של הרשת החברתית המתחרה, סניילצ'אט.<br>
    רשימת המשתמשים נראית כך:
</p>
End of explanation
"""


our_users = []
for user_details in snailchat_users:
    new_user = User(*user_details)  # Unpacking – התא הראשון עובר לפרמטר התואם, וכך גם השני, השלישי והרביעי
    our_users.append(new_user)
    print(new_user)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    נניח, לכאורה בלבד, שאנחנו רוצים להעתיק את אותה רשימת משתמשים ולצרף אותה לרשת החברתית שלנו.<br>
    קחו דקה וחשבו איך הייתם עושים את זה.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    זכרו שקריאה למחלקה <var>User</var> היא ככל קריאה לפונקציה אחרת,<br>
    ושהמופע שחוזר ממנה הוא ערך בדיוק כמו כל ערך אחר.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נוכל ליצור רשימת מופעים של משתמשים. לדוגמה:
</p>
End of explanation
"""


print(our_users[0])
print(our_users[1])
print(our_users[2])

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    בקוד שלמעלה יצרנו רשימה ריקה, שאותה נמלא במשתמשים <strike>שנגנוב</strike> שנשאיל מסניילצ'אט.<br>
    נעביר את הפרטים של כל אחד מהמשתמשים המופיעים ב־<var>snailchat_users</var>, ל־<code>__init__</code> של <var>User</var>,<br>
    ונצרף את המופע החדש שנוצר לתוך הרשימה החדשה שיצרנו.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    עכשיו הרשימה <var>our_users</var> היא רשימה לכל דבר, שכוללת את כל המשתמשים החדשים שהצטרפו לרשת החברתית שלנו:
</p>
End of explanation
"""


class User:
    def __init__(self, first_name, last_name, nickname, current_age):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = nickname
        self.age = current_age
    
    def celebrate_birthday(self):
        age = age + 1

    def __str__(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'

"""
Explanation: <div class="align-center" style="display: flex; text-align: right; direction: rtl; clear: both;">
    <div style="display: flex; width: 10%; float: right; clear: both;">
        <img src="images/exercise.svg" style="height: 50px !important;" alt="תרגול"> 
    </div>
    <div style="width: 70%">
        <p style="text-align: right; direction: rtl; float: right; clear: both;">
            צרו את רשימת כל הנקודות שה־x וה־y שלהן הוא מספר שלם בין 0 ל־6.<br>
            לדוגמה, רשימת כל הנקודות שה־x וה־y שלהן הוא בין 0 ל־2 היא:<br>
            <samp dir="ltr">[(0, 0), (0, 1), (1, 0), (1, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)]</samp>
        </p>
    </div>
    <div style="display: flex; width: 20%; border-right: 0.1rem solid #A5A5A5; padding: 1rem 2rem;">
        <p style="text-align: center; direction: rtl; justify-content: center; align-items: center; clear: both;">
            <strong>חשוב!</strong><br>
            פתרו לפני שתמשיכו!
        </p>
    </div>
</div>

<span style="text-align: right; direction: rtl; float: right; clear: both;">טעויות נפוצות</span>
<span style="text-align: right; direction: rtl; float: right; clear: both;">גבולות מרחב הערכים</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נסקור כמה דוגמאות כדי לוודא שבאמת הבנו כיצד מתנהגות מחלקות.<br>
    נגדיר את מחלקת <var>User</var> שאנחנו מכירים, ונצרף לה את הפעולה <var>celebrate_birthday</var>, שכזכור, מגדילה את גיל המשתמש ב־1:
</p>
End of explanation
"""


user6 =  User('Winston', 'Smith', 'Jeeves', 39)
user6.celebrate_birthday()

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    ניסיון ליצור מופע של משתמש ולחגוג לו יום הולדת יגרום לשגיאה.<br>
    תוכלו לנחש מה תהיה השגיאה עוד לפני שתריצו?
</p>
End of explanation
"""


class User:
    def __init__(self, first_name, last_name, nickname, current_age):
        self.first_name = first_name
        self.last_name = last_name
        self.nickname = nickname
        self.age = current_age
    
    def celebrate_birthday(self):
        self.age = self.age + 1

    def __str__(self):
        full_name = f'{self.first_name} {self.last_name}'
        return f'{self.nickname} ({full_name}) is {self.age} years old.'


user6 =  User('Winston', 'Smith', 'Jeeves', 39)
print(f"User before birthday: {user6}")
user6.celebrate_birthday()
print(f"User after  birthday: {user6}")

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    ניסינו לשנות את המשתנה <var>age</var> – אך הוא אינו מוגדר.<br>
    כדי לשנות את הגיל של המשתמש שיצרנו, נהיה חייבים להתייחס ל־<code>self.age</code>.<br>
    אם לא נציין במפורש שאנחנו רוצים לשנות את התכונה <var>age</var> ששייכת ל־<var>self</var>, פייתון לא תדע לאיזה מופע אנחנו מתכוונים.<br>
    נתקן:
</p>
End of explanation
"""


user6 =  User('Winston', 'Smith', 'Jeeves', 39)
print(user6)
age = 10
print(user6)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    באותה המידה, תכונות שהוגדרו כחלק ממופע לא מוגדרות מחוצה לו.<br>
    אפשר להשתמש, לדוגמה, בשם המשתנה <var>age</var> מבלי לחשוש לפגוע בתפקוד המחלקה או בתפקוד המופעים:
</p>
End of explanation
"""


user6.age = 10
print(user6)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    כדי לשנות את גילו של המשתמש, נצטרך להתייחס אל התכונה שלו בצורת הכתיבה שלמדנו:
</p>
End of explanation
"""


class Dice:
    def __init__(self, number):
        if 1 <= number <= 6:
            self.is_valid = True


dice_bag = [Dice(roll_result) for roll_result in range(7)]

"""
Explanation: <span style="text-align: right; direction: rtl; float: right; clear: both;">תכונה או פעולה שלא קיימות</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    שגיאה שמתרחשת לא מעט היא פנייה לתכונה או לפעולה שלא קיימות עבור המופע.<br>
    לדוגמה:
</p>
End of explanation
"""


for dice in dice_bag:
    print(dice.is_valid)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    יצרנו רשימת קוביות וביצענו השמה כך ש־<var>dice_bag</var> תצביע עליה.<br>
    כעת נדפיס את התכונה <var>is_valid</var> של כל אחת מהקוביות:
</p>
End of explanation
"""


class Dice:
    def __init__(self, number):
        self.is_valid = (1 <= number <= 6)  # לא חייבים סוגריים


dice_bag = [Dice(roll_result) for roll_result in range(7)]
for dice in dice_bag:
    print(dice.is_valid)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    הבעיה היא שהקוביה הראשונה שיצרנו קיבלה את המספר 0.<br>
    במקרה כזה, התנאי בפעולת האתחול (<code>__init__</code>) לא יתקיים, והתכונה <var>is_valid</var> לא תוגדר.<br>
    כשהלולאה תגיע לקובייה 0 ותנסה לגשת לתכונה <var>is_valid</var>, נגלה שהיא לא קיימת עבור הקובייה 0, ונקבל <var>AttributeError</var>.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נתקן:
</p>
End of explanation
"""


import os


class Path:
    def __init__(self, path):
        self.fullpath = path
        self.parts = list(self.get_parts())

    def get_parts(self):
        current_part = ""
        for char in self.fullpath:
            if char in r"\/":
                yield current_part
                current_part = ""
            else:
                current_part = current_part + char
        if current_part != "":
            yield current_part

    def get_drive_letter(self):
        return self.parts[0].rstrip(":")

    def get_dirname(self):
        path = "/".join(self.parts[:-1])
        return Path(path)

    def get_basename(self):
        return self.parts[-1]

    def get_extension(self):
        name = self.get_basename()
        i = name.rfind('.')
        if 0 < i < len(name) - 1:
            return name[i + 1:]
        return ''

    def is_exists(self):
        return os.path.exists(str(self))

    def normalize_path(self):
        normalized = "\\".join(self.parts)
        return normalized.rstrip("\\")

    def info_message(self):
        return f"""
            Some info about "{self}":
            Drive letter: {self.get_drive_letter()}
            Dirname: {self.get_dirname()}
            Last part of path: {self.get_basename()}
            File extension: {self.get_extension()}
            Is exists?: {self.is_exists()}
        """.strip()

    def __str__(self):
        return self.normalize_path()


EXAMPLES = (
    r"C:\Users\Yam\python.jpg",
    r"C:/Users/Yam/python.jpg",
    r"C:",
    r"C:\\",
    r"C:/",
    r"C:\Users/",
    r"D:/Users/",
    r"C:/Users",
)
for example in EXAMPLES:
    path = Path(example)
    print(path.info_message())
    print()

"""
Explanation: <span style="text-align: right; direction: rtl; float: right; clear: both;">סיכום</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    במחברת זו רכשנו כלים לעבודה עם מחלקות ועצמים, ולייצוג אוספים של תכונות ופעולות.<br>
    כלים אלו יעזרו לנו לארגן טוב יותר את התוכנית שלנו ולייצג ישויות מהעולם האמיתי בצורה אינטואיטיבית יותר.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נהוג לכנות את עולם המחלקות בשם "<dfn>תכנות מונחה עצמים</dfn>" (<dfn>Object Oriented Programming</dfn>, או <dfn>OOP</dfn>).<br>
    זו פרדיגמת תכנות הדוגלת ביצירת מחלקות לצורך חלוקת קוד טובה יותר,<br>
    ובתיאור עצמים מהעולם האמיתי בצורה טובה יותר, כאוספים של תכונות ופעולות.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    תכנות מונחה עצמים הוא פיתוח מאוחר יותר של פרדיגמת תכנות אחרת שאתם כבר מכירים, הנקראת "<dfn>תכנות פרוצדורלי</dfn>".<br>
    פרדיגמה זו דוגלת בחלוקת הקוד לתתי־תוכניות קטנות (מה שאתם מכירים כפונקציות), כדי ליצור קוד שמחולק טוב יותר וקל יותר לתחזוק.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    פייתון תומכת הן בתכנות פרוצדורלי והן בתכנות מונחה עצמים.
</p>

<span style="text-align: right; direction: rtl; float: right; clear: both;">מונחים</span>
<dl style="text-align: right; direction: rtl; float: right; clear: both;">
    <dt>מחלקה (Class)</dt>
    <dd>
        תבנית, או שבלונה, שמתארת אוסף של תכונות ופעולות שיש ביניהן קשר.<br>
        המחלקה מגדירה מבנה שבעזרתו נוכל ליצור בקלות עצם מוגדר, שוב ושוב.<br>
        לדוגמה: מחלקה המתארת משתמש ברשת חברתית, מחלקה המתארת כלי רכב, מחלקה המתארת נקודה במישור.
    </dd>
    <dt>מופע (Instance)</dt>
    <dd>
        נקרא גם <dfn>עצם</dfn> (<dfn>Object</dfn>).<br>
        ערך שנוצר על ידי מחלקה כלשהי. סוג הערך ייקבע לפי המחלקה שיצרה אותו.<br>
        הערך נוצר לפי התבנית ("השבלונה") של המחלקה שממנה הוא נוצר, ומוצמדות לו הפעולות שהוגדרו במחלקה.<br>
        המופע הוא יחידה עצמאית שעומדת בפני עצמה. לרוב מחלקה תשמש אותנו ליצירת מופעים רבים.<br>
        לדוגמה: המופע "נקודה שנמצאת ב־<span dir="ltr">(5, 3)</span>" יהיה מופע שנוצר מהמחלקה "נקודה". 
    </dd>
    <dt>תכונה (Property, Member)</dt>
    <dd>
        ערך אופייני למופע שנוצר מהמחלקה.<br>
        משתנים השייכים למופע שנוצר מהמחלקה, ומכילים ערכים שמתארים אותו.<br>
        לדוגמה: לנקודה במישור יש ערך x וערך y. אלו 2 תכונות של הנקודה.<br>
        נוכל להחליט שתכונותיה של מחלקת מכונית יהיו צבע, דגם ויצרן.
    </dd>
    <dt>פעולה (Method)</dt>
    <dd>
        פונקציה שמוגדרת בגוף המחלקה.<br>
        מתארת התנהגויות אפשריות של המופע שייווצר מהמחלקה.<br>
        לדוגמה: פעולה על נקודה במישור יכולה להיות מציאת מרחקה מראשית הצירים.<br>
        פעולה על שולחן יכולה להיות "קצץ 5 סנטימטר מגובהו".
    </dd>
    <dt>שדה (Field, Attribute)</dt>
    <dd>
        שם כללי הנועד לתאר תכונה או פעולה.<br>
        שדות של מופע מסוים יהיו כלל התכונות והפעולות שאפשר לגשת אליהן מאותו מופע.<br>
        לדוגמה: השדות של נקודה יהיו התכונות x ו־y, והפעולה שבודקת את מרחקה מראשית הצירים.
    </dd>
    <dt>פעולה מיוחדת (Special Method)</dt>
    <dd>
        ידועה גם כ־<dfn>dunder method</dfn> (double under, קו תחתון כפול) או כ־<dfn>magic method</dfn> (פעולת קסם).<br>
        פעולה שהגדרתה במחלקה גורמת למחלקה או למופעים הנוצרים ממנה להתנהגות מיוחדת.<br>
        דוגמאות לפעולות שכאלו הן <code>__init__</code> ו־<code>__str__</code>.
    </dd>
    <dt>פעולת אתחול (Initialization Method)</dt>
    <dd>
        פעולה שרצה עם יצירת מופע חדש מתוך מחלקה.<br>
        לרוב משתמשים בפעולה זו כדי להזין במופע ערכים התחלתיים.
    </dd>
    <dt>תכנות מונחה עצמים (Object Oriented Programming)</dt>
    <dd>
        פרדיגמת תכנות שמשתמשת במחלקות בקוד ככלי העיקרי להפשטה של העולם האמיתי.<br>
        בפרדיגמה זו נהוג ליצור מחלקות המייצגות תבניות של עצמים, ולאפיין את העצמים באמצעות תכונות ופעולות.<br>
        בעזרת המחלקות אפשר ליצור מופעים, שהם ייצוג של פריט בודד (עצם, אובייקט) שנוצר לפי תבנית המחלקה.
    </dd>
</dl>

<span style="text-align: right; direction: rtl; float: right; clear: both;">תרגיל לדוגמה</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    כתבו מחלקה המייצגת נתיב תקין במערכת ההפעלה חלונות.<br>
    הנתיב מחולק לחלקים באמצעות התו / או התו \.<br>
    החלק הראשון בנתיב הוא תמיד אות הכונן ואחריה נקודתיים.<br>
    החלקים שנמצאים אחרי החלק הראשון, ככל שיש כאלו, הם תיקיות וקבצים.<br>
    דוגמאות לנתיבים תקינים:
</p>

<ul style="text-align: right; direction: rtl; float: right; clear: both;">
    <li><span dir="ltr">C:\Users\Yam\python.jpg</span></li>
    <li><span dir="ltr">C:/Users/Yam/python.jpg</span></li>
    <li><span dir="ltr">C:</span></li>
    <li><span dir="ltr">C:\</span></li>
    <li><span dir="ltr">C:/</span></li>
    <li><span dir="ltr">C:\User/</span></li>
    <li><span dir="ltr">D:/User/</span></li>
    <li><span dir="ltr">C:/User</span></li>
  </ul>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    המחלקה תכלול את הפעולות הבאות:
</p>
<ul style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>אחזר את אות הכונן בעזרת הפעולה <var>get_drive_letter</var>.</li>
    <li>אחזר את הנתיב ללא חלקו האחרון בעזרת הפעולה <var>get_dirname</var>.</li>
    <li>אחזר את שם החלק האחרון בנתיב, בעזרת הפעולה <var>get_basename</var>.</li>
    <li>אחזר את סיומת הקובץ בעזרת הפעולה <var>get_extension</var>.</li>
    <li>אחזר אם הנתיב קיים במחשב בעזרת הפעולה <var>is_exists</var>.</li>
    <li>אחזר את הנתיב כולו כמחרוזת, כשהתו המפריד הוא <samp>/</samp>, וללא <samp>/</samp> בסוף הנתיב.</li>
</ul>
End of explanation
"""


def cast_multiple_votes(poll, votes):
    for vote in votes:
        poll.vote(vote)


bridge_question = Poll('What is your favourite colour?', ['Blue', 'Yellow'])
cast_multiple_votes(bridge_question, ['Blue', 'Blue', 'Yellow'])
print(bridge_question.get_winner() == 'Blue')
cast_multiple_votes(bridge_question, ['Yellow', 'Yellow'])
print(bridge_question.get_winner() == 'Yellow')
print(bridge_question.get_votes() == [('Yellow', 3), ('Blue', 2)])
bridge_question.remove_option('Yellow')
print(bridge_question.get_winner() == 'Blue')
print(bridge_question.get_votes() == [('Blue', 2)])
bridge_question.add_option('Yellow')
print(bridge_question.get_votes() == [('Blue', 2), ('Yellow', 0)])
print(not bridge_question.add_option('Blue'))
print(bridge_question.get_votes() == [('Blue', 2), ('Yellow', 0)])

"""
Explanation: <span style="text-align: right; direction: rtl; float: right; clear: both;">תרגילים</span>
<span style="text-align: right; direction: rtl; float: right; clear: both;">סקרנות</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    מחלקת המוצר בצ'יקצ'וק החליטה להוסיף פיצ'ר שמאפשר למשתמשים ליצור סקרים, וכרגיל כל העבודה נופלת עליכם.<br>
    כתבו מחלקה בשם <var>Poll</var> שמייצגת סקר.<br>
    פעולת האתחול של המחלקה תקבל כפרמטר את שאלת הסקר, וכפרמטר נוסף iterable עם כל אפשרויות ההצבעה לסקר.<br>
    כל אפשרות הצבעה בסקר מיוצגת על ידי מחרוזת.<br>
    המחלקה תכיל את הפעולות הבאות: 
</p>

<ol style="text-align: right; direction: rtl; float: right; clear: both;">
    <li><var>vote</var> שמקבלת כפרמטר אפשרות הצבעה לסקר ומגדילה את מספר ההצבעות בו ב־1.</li>
    <li><var>add_option</var>, שמקבלת כפרמטר אפשרות הצבעה לסקר ומוסיפה אותה.</li>
    <li><var>remove_option</var> שמקבלת כפרמטר אפשרות הצבעה לסקר ומוחקת אותה.</li>
    <li><var>get_votes</var> המחזירה את כל האפשרויות כרשימה של tuple, המסודרים לפי כמות ההצבעות.<br>
        בכל tuple התא הראשון יהיה שם האפשרות בסקר, והתא השני יהיה מספר ההצבעות.</li>
    <li><var>get_winner</var> המחזירה את שם האפשרות שקיבלה את מרב ההצבעות.</li>
</ol>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    במקרה של תיקו, החזירו מ־<var>get_winner</var> את אחת האפשרויות המובילות.<br>
    החזירו מהפעולות <var>vote</var>, <var>add_option</var> ו־<var>remove_option</var> את הערך <samp>True</samp> אם הפעולה עבדה כמצופה.<br> 
    במקרה של הצבעה לאפשרות שאינה קיימת, מחיקת אפשרות שאינה קיימת או הוספת אפשרות שכבר קיימת, החזירו <samp>False</samp>.<br>
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
ודאו שהקוד הבא מדפיס רק <samp>True</samp> עבור התוכנית שכתבתם:
</p>
End of explanation
"""


