def silly_generator():
    a = 1
    yield a
    b = a + 1
    yield b
    c = [1, 2, 3]
    yield c

"""
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;">Generators</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>
    הערך הזה יכול היה להיות מכל טיפוס שהוא: בוליאני, מחרוזת, tuple וכדומה.<br>
    אם נרצה להחזיר כמה ערכים יחד, תמיד נוכל להחזיר אותם כרשימה או כ־tuple.<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>מילות כל השירים שראו אור מאז שנת 1400 לספירה.</li>
    <li>כל המספרים השלמים הגדולים מ־0.</li>
</ul>

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

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

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


print(silly_generator())

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    מעניין! זה נראה ממש כמו פונקציה. נקרא למבנה הזה שיצרנו "<dfn>פונקציית ה־generator</dfn>".<br>
    אבל מהו ה־<code>yield</code> המוזר הזה שנמצא שם?
</p>

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


our_generator = silly_generator()

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

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


next_value = next(our_generator)
print(next_value)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    בעקבות הקריאה ל־<code>silly_generator</code> נוצר לנו סמן שמצביע כרגע על השורה <code>a = 1</code>.<br>
    המינוח המקצועי לסמן הזה הוא <dfn>generator iterator</dfn>.
</p>

<img src="images/silly_generator1.png?v=1" width="300px" style="display: block; margin-left: auto; margin-right: auto;" alt="תוכן הפונקציה silly_generator, כאשר חץ מצביע לשורה הראשונה שלה – a = 1">
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    אחרי שהרצנו את השורה <code dir="ltr">our_generator = silly_generator()</code>, הסמן המדובר נשמר במשתנה בשם <var>our_generator</var>.<br>
    זה זמן מצוין לבקש מה־generator להחזיר ערך.<br>
    נעשה זאת בעזרת הפונקציה הפייתונית <code>next</code>:
</p>
End of explanation
"""


print(next(our_generator))

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    כדי להבין מה התרחש נצטרך להבין שני דברים חשובים שקשורים ל־generators:<br>
</p>
<ol style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>קריאה ל־<code>next</code> היא כמו לחיצה על "נגן" (Play) – היא גורמת לסמן לרוץ עד שהוא מגיע לשורה של החזרת ערך.</li>
    <li>מילת המפתח <code>yield</code> דומה למילת המפתח <code>return</code> – היא מפסיקה את ריצת הסמן, ומחזירה את הערך שמופיע אחריה.</li>
</ol>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    אז היה לנו סמן שהצביע על השורה הראשונה. לחצנו Play, והוא הריץ את הקוד עד שהוא הגיע לנקודה שבה מחזירים ערך.<br>
    ההבדל בין פונקציה לבין generator, הוא ש<mark>כשאנחנו מחזירים ערך בעזרת <code>yield</code> אנחנו "מקפיאים" את המצב שבו
    יצאנו מהפונקציה.</mark><br>
    ממש כמו ללחוץ על "Pause".<br>
    כשנקרא ל־<code>next</code> בפעם הבאה – הפונקציה תמשיך לרוץ מאותו המקום שבו השארנו את הסמן, עם אותם ערכי משתנים.<br>
    עכשיו הסמן מצביע על השורה <code>b = a + 1</code>, ומחכה שמישהו יקרא שוב ל־<code>next</code> כדי שהפונקציה תוכל להמשיך לרוץ:
</p>
End of explanation
"""


print(next(our_generator))

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    נסכם מה קרה עד עכשיו:
</p>

<ol style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>הגדרנו פונקציה בשם <var>silly_generator</var>, שאמורה להחזיר את הערכים <samp>1</samp>, <samp>2</samp> ו־<samp dir="ltr">[1, 2, 3]</samp>. קראנו לה "<em>פונקציית הגנרטור</em>".</li>
    <li>בעזרת קריאה לפונקציית הגנרטור, יצרנו "סמן" (generator iterator) שנקרא <var>our_generator</var> ומצביע לשורה הראשונה בפונקציה.</li>
    <li>בעזרת קריאה ל־<code>next</code> על ה־generator iterator, הרצנו את הסמן עד שה־generator החזיר ערך.</li>
    <li>למדנו ש־generator־ים מחזירים ערכים בעיקר בעזרת yield – שמחזיר ערך ושומר את המצב שבו הפונקציה עצרה.</li>
    <li>קראנו שוב ל־<code>next</code> על ה־generator iterator, וראינו שהוא ממשיך מהמקום שבו ה־generator הפסיק לרוץ פעם קודמת.</li>
</ol>

<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>next(our_generator)</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>

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


print(next(our_generator))

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


our_generator = silly_generator()
print(next(our_generator))
print(next(our_generator))
print(next(our_generator))

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


our_generator = silly_generator()
for item in our_generator:
    print(item)

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

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


for item in our_generator:
    print(item)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    מה מתרחש כאן?<br>
    אנחנו מבקשים מלולאת ה־<code>for</code> לעבור על ה־generator iterator שלנו.<br>
    ה־<code>for</code> עושה עבורנו את העבודה אוטומטית:
</p>

<ol style="text-align: right; direction: rtl; float: right; clear: both;">
    <li>הוא מבקש את האיבר הבא מה־generator iterator באמצעות <code>next</code>.</li>
    <li>הוא מכניס את האיבר שהוא קיבל מה־generator ל־<var>item</var>.</li>
    <li>הוא מבצע את גוף הלולאה פעם אחת עבור האיבר שנמצא ב־<var>item</var>.</li>
    <li>הוא חוזר לראש הלולאה שוב, ומנסה לקבל את האיבר הבא באמצעות <code>next</code>. כך עד שייגמרו האיברים ב־generator iterator.</li>
</ol>

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


our_generator = silly_generator()
items = list(our_generator)
print(items)

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

<span style="text-align: right; direction: rtl; float: right; clear: both;">המרת טיפוסים</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    דרך אחרת, לדוגמה, היא לבקש להמיר את ה־generator iterator לסוג משתנה אחר שהוא גם iterable:
</p>
End of explanation
"""


print(list(our_generator))

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


def my_range(upper_limit):
    numbers = []
    current_number = 0
    while current_number < upper_limit:
        numbers.append(current_number)
        current_number = current_number + 1
    return numbers


for number in my_range(1000):
    print(number)

"""
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;">
נכתוב פונקציה רגילה שמקבלת מספר שלם, ומחזירה רשימה של כל המספרים השלמים מ־0 ועד אותו מספר (נשמע לכם מוכר?):
</p>
End of explanation
"""


def my_range(upper_limit):
    current_number = 0
    while current_number < upper_limit:
        yield current_number
        current_number = current_number + 1


our_generator = my_range(1000)
for number in our_generator:
    print(number)

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

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


def square_numbers(numbers):
    squared_numbers = []
    for number in numbers:
        squared_numbers.append(number ** 2)
    return squared_numbers


for number in square_numbers(my_range(1000)):
    print(number)

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    שימו לב כמה הגרסה הזו אלגנטית יותר!<br>
    בכל פעם אנחנו פשוט שולחים את ערכו של מספר אחד (<var>current_number</var>) החוצה.<br>
    כשמבקשים את הערך הבא מה־generator iterator, פונקציית ה־generator חוזרת לעבוד מהנקודה שבה היא עצרה:<br>
    היא מעלה את ערכו של המספר הנוכחי, בודקת אם הוא נמוך מ־<var>upper_limit</var>, ושולחת גם אותו החוצה.<br>
    בשיטה הזו, <code>my_range(numbers)</code> לא מחזירה לנו רשימה של התוצאות – אלא generator iterator שמחזיר ערך אחד בכל פעם.<br>
    כך אנחנו לעולם לא מחזיקים בזיכרון 1,000 מספרים בו־זמנית.
</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;">
            לפניכם פונקציה שמקבלת רשימה, ומחזירה עבור כל מספר ברשימה את ערכו בריבוע.<br>
            זוהי גרסה מעט בזבזנית שמשתמשת בהרבה זיכרון. תוכלו להמיר אותה להיות generator?
        </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>
End of explanation
"""


def find_pythagorean_triples(upper_bound=10_000):
    pythagorean_triples = []
    for c in range(3, upper_bound):
        for b in range(2, c):
            for a in range(1, b):
                if a ** 2 + b **2 == c ** 2:
                    pythagorean_triples.append((a, b, c))
    return pythagorean_triples


for triple in find_pythagorean_triples():
    print(triple)

"""
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>
    במקרה כזה, נוכל להשתמש ב־generator כדי לקבל חלק מהתוצאה בזמן אמת,<br>
    בזמן שבפונקציה "רגילה" נצטרך להמתין עד סיום החישוב כולו.
</p>

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    שלשה פיתגורית, לדוגמה, היא שלישיית מספרים שלמים וחיוביים, $a$, $b$ ו־$c$, שעונים על הדרישה $a^2 + b^2 = c^2$.<br>
    אם כך, כדי ששלושה מספרים שאנחנו בוחרים ייחשבו שלשה פיתגורית,<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>$(3, 4, 5)$, כיוון ש־$9 + 16 = 25$.<br>
        9 הוא 3 בריבוע, 16 הוא 4 בריבוע ו־25 הוא 5 בריבוע.
    </li>
    <li>$(5, 12, 13)$, כיוון ש־$25 + 144 = 169$.</li>
    <li>$(8, 15, 17)$, כיוון ש־$64 + 225 = 289$.</li>
</ul>

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


def find_pythagorean_triples(upper_bound=10_000):
    for c in range(3, upper_bound):
        for b in range(2, c):
            for a in range(1, b):
                if a ** 2 + b **2 == c ** 2:
                    yield a, b, c


for triple in find_pythagorean_triples():
    print(triple)

"""
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;">
            הרצת התא הקודם תתקע את המחברת (חישוב התוצאה יימשך זמן רב).<br>
            כדי להיות מסוגלים להריץ את התאים הבאים, לחצו <samp>00</samp> לאחר הרצת התא, ובחרו <em>Restart</em>.<br>
            אל דאגה – האתחול יתבצע אך ורק עבור המחברת, ולא עבור מחשב.
        </p>
    </div>
</div>

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


def fibonacci(max_items):
    a = 1
    b = 1
    numbers = [1, 1]
    while len(numbers) < max_items:
        a, b = b, a + b  # Unpacking
        numbers.append(b)
    return numbers


for number in fibonacci(10):
    print(number)

"""
Explanation: <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;">
    להזכירכם, ה־generator שולח את התוצאה החוצה מייד כשהוא מוצא שלשה אחת,<br>
    וה־for מקבל מה־generator iterable כל שלשה ברגע שהיא נמצאה.<br>
    ברגע שה־for מקבל שלשה, הוא מבצע את גוף הלולאה עבור אותה שלשה, ורק אז מבקש מ־generator את האיבר הבא.<br>
    בגלל האופי של generators, הקוד בתא האחרון מדפיס לנו כל שלשה ברגע שהוא מצא אותה, ולא מחכה עד שיימצאו כל השלשות.
</p>

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

<p style="text-align: right; direction: rtl; float: right; clear: both;">
    עליכם לכתוב פונקציה שמקבלת מספר חיובי שלם $n$, ומחזירה קבוצת מספרים שמכפלתם (תוצאת הכפל ביניהם) היא $n$.<br>
    לדוגמה, המספר 1,386 בנוי מהמכפלה של קבוצת המספרים $2 \cdot 3 \cdot 3 \cdot 7 \cdot 11$.<br>
    כל מספר בקבוצת המספרים הזו חייב להיות ראשוני.<br>
    להזכירכם: מספר ראשוני הוא מספר שאין לו מחלקים חוץ מעצמו ומ־1.
</p>

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

<p style="text-align: right; direction: rtl; float: right; clear: both;">    
    רמז: <span style="background: black;">אם תנסו לחלק את המספר ב־2, ואז ב־3 (וכן הלאה), בסופו של דבר תגיעו למחלק ראשוני של המספר.</span><br>
    רמז עבה: <span style="background: black;">בכל פעם שמצאתם מחלק אחד למספר, חלקו את המספר במחלק, והתחילו את החיפוש מחדש. מתי עליכם לעצור?</span>
</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>
    $1, 1, 2, 3, 5, 8, \ldots$
</p>

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


def fibonacci():
    a = 1
    b = 1
    numbers = [1, 1]
    while True:  # תמיד מתקיים
        yield a
        a, b = b, a + b

        
generator_iterator = fibonacci()
for number in range(10):
    print(next(generator_iterator))

# אני יכול לבקש בקלות רבה את 10 האיברים הבאים בסדרה
for number in range(10):
    print(next(generator_iterator))

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


def simple_generator():
    yield 1
    yield 2
    yield 3

"""
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;">
            generators אין־סופיים יכולים לגרום בקלות ללולאות אין־סופיות, גם בלולאות <code>for</code>.<br>
            שימו לב לצורת ההתעסקות העדינה בדוגמאות למעלה.<br>
            הרצת לולאת <code>for</code> ישירות על ה־generator iterator הייתה מכניסה אותנו ללולאה אין־סופית.
        </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;">
            כתבו generator שמחזיר את כל המספרים השלמים הגדולים מ־0.
        </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;">ריבוי generator iterators</span>
<p style="text-align: right; direction: rtl; float: right; clear: both;">
    נגדיר generator פשוט שמחזיר את האיברים <samp>1</samp>, <samp>2</samp> ו־<samp>3</samp>:
</p>
End of explanation
"""


first_gen = simple_generator()
second_gen = simple_generator()

"""
Explanation: <p style="text-align: right; direction: rtl; float: right; clear: both;">
    ניצור שני generator iterators ("סמנים") שונים שמצביעים לשורה הראשונה של ה־generator שמופיע למעלה:
</p>
End of explanation
"""


print(next(first_gen))
print(next(second_gen))

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


print(next(first_gen))
print(next(first_gen))

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


print(next(second_gen))

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


