השוואת פיתרונות קורס Python

,אוקיי,
אז אני מבין שבתוכנית הנוכחית הפונקציה __init__ מופעלת כל פעם שיוצרים אובייקט ( כתבת: “ממחלקה - כל מחלקה”. מה הכוונה כל מחלקה? אצלינו מדובר על המחלקה MyCounter . אין עוד מחלקות בתוכנית…)
בנוסף, ראיתי בדוגמאות שנתת , למשל בתוכנית המחשבת את המע"מ - שאין במחלקה בכלל פונקציה __init__ . אם כך מדוע? מתי צריך את זה ומתי לא?

תרגיל 3 מחלקות ואובייקטים


class Widget(object):
    def __init__(self,name):
        self.name = name
        self.item = False
        self.args = []
    def add_dependency(self,*args):
        if self.item:return
        self.args = [i for i in args]
        self.item = True

    def build(self):
        names = []
        names = [i.name for i in self.args]
        print (', '.join(names))



luke    = Widget("Luke")
hansolo = Widget("Han Solo")
leia    = Widget("Leia")
yoda    = Widget("Yoda")
padme   = Widget("Padme Amidala")
anakin  = Widget("Anakin Skywalker")
obi     = Widget("Obi-Wan")
darth   = Widget("Darth Vader")
_all    = Widget("All")

luke.add_dependency(hansolo, leia, yoda)
leia.add_dependency(padme, anakin)
obi.add_dependency(yoda)
darth.add_dependency(anakin)

_all.add_dependency(luke, hansolo, leia, yoda, padme, anakin, obi, darth)
_all.build()

הי,

נראה לי שלא הבנת נכון את תרגיל 3-

המטרה שכל אוביקט יודפס אחרי כל האוביקטים האחרים שהוא תלוי בהם,

כלומר בדוגמא שלנו האוביקט Luke תלוי באוביקטים Han Solo, Leia ו Yoda לכן בהדפסה הוא חייב להופיע אחרי שלושתם
(אני יודע שהוא תלוי בהם לפי השורה:

luke.add_dependency(hansolo, leia, yoda)

לשאלה שלך על __init__ - זו פונקציה אופציונאלית כלומר לא חייבים להגדיר אותה, אבל אם מגדירים היא תופעל לכל אוביקט חדש שנוצר.

טוב אני מנסה לשפר זאת ע"י שינוי הפונקציה build
הוספתי לולאה נוספת שרצה על כל תתי הרכיבים שנמצאים תחת רכיב האב.
כעת יש לי 2 בעיות:

  1. מה אני עושה עם רכיב שאין לו תתי רכיבים?
  2. נראה לי שזה לא עובד כי יש לי פערים עם כתיב נכון
        def build(self):
        names = []
         for i in self.args:
            for j in i:
                if j.name not in names:
                    names.append(j.name)
            if i.name not in names:
                names.append(i.name)
        print (', '.join(names))

כרגע הודאת השגיאה שקיבלתי היא:

TypeError: 'Widget' object is not iterable

אם אני מבין נכון זה אומר שאני לא יכול לרוץ על הרכיבים שבתוך האובייקט.
אם כך, איך אני מגיע לתתי הרכיבים?
אשמח להכוונה
תודה

תוכל בבקשה להחליף את כל שמות המשתנים למשהו ברור יותר (במקום i, j, args, names וכו)? יהיה הרבה יותר קל כך לקרוא ולהבין על מה אנחנו מדברים

החלפתי את שמות המשתנים. מקווה שעכשיו יהיה יותר מובן.
מה שניסיתי לעשות הוא לעבור על תתי הרכיבים ולהוסיפם לרשימת ההדפסה ולאחר מכן לעבור על הרכיבים עצמם ולהוסיפם לאותה רשימה.
למשל אם מדובר על האובייקט all אם שולחים את המשתנה luke שמכיל בתוכו 3 תתי רכיבים , כאשר הוא נכנס לפונקצית build בודקים - ע"י לולאת פור כפולה - אם הוא מכיל תתי רכיבים ואם כן מוסיפים אותם לרשימה ואח"כ מוסיפים אותו לרשימה (כדי שהוא יודפס לאחריהם כמבוקש בתרגיל).
הבעיה היא שאני לא יודע איך לכתוב את זה נכון כי כאשר אני מנסה לעבור על luke למשל אני מקבל הודעת שגיאה שהוא לא iterable.

class Widget(object):
    def __init__(self,name):
        self.name = name
        self.already_exist = False
        self.objects = []
    def add_dependency(self,*sub_names):
        if self.already_exist:return
        self.objects = [i for i in sub_names]
        self.already_exist = True

    def build(self):
        print_list = []
        for sub_name in self.objects:
            for item in sub_name:
                if item.name not in print_list:
                    print_list.append(item.name)
            if sub_name.name not in print_list:
                print_list.append(sub_name.name)
        print (', '.join(print_list))



luke    = Widget("Luke")
hansolo = Widget("Han Solo")
leia    = Widget("Leia")
yoda    = Widget("Yoda")
padme   = Widget("Padme Amidala")
anakin  = Widget("Anakin Skywalker")
obi     = Widget("Obi-Wan")
darth   = Widget("Darth Vader")
_all    = Widget("All")

luke.add_dependency(hansolo, leia, yoda)
leia.add_dependency(padme, anakin)
obi.add_dependency(yoda)
darth.add_dependency(anakin)

_all.add_dependency(luke, hansolo, leia, yoda, padme, anakin, obi, darth)
_all.build()

תזכור שלכל רכיב יש פונקציית build שכבר עושה את הלולאה. נסה לקרוא לה במקום הלולאה הפנימית
(וכן אני יודע שזה נשמע מוזר כי אתה בדיוק כותב את הקוד של הפונקציה build, אבל כמו שאומר השיר תחשוב טוב יהיה טוב)

הי,

מחדד את ההודעה הקודמת-

בתוך הפונקציה build יש לך ביד משתנה בשם sub_name שהוא אוביקט הרכיב שעכשיו אתה צריך לבנות.

אתה מנסה להפעיל לולאה פנימית שתחפש את כל ה sub_names של אותו רכיב פנימי, ואני חושב שזו טעות. במקום זה תזכור ש sub_name הוא בעצמו אוביקט Widget ולכן יש לו פונקציה build משלו. נסה להפעיל אותה ותראה מה קורה
(ואם זה לא עובד שים פה את הקוד שלא עובד ונמשיך לעבוד עליו)

טוב אז כמו שכתבתי לך הסתבכתי כהוגן עם התוכנית הזו.
חבר הראה לי הצעה שלו לפתרון וניסיתי להבין אותה איתו ביחד.
אני יודע שזה לא שלי אבל לפחות ניסיתי להבין את זה.
אני בטוח שיש גם דרכים אחרות ואשמח לנסות בהנחייתך דרך אחרת כי גם כשהבנתי זאת אני לא מרגיש שאני יכול לכתוב לבד אחת וזה די מבאס אותי.

class Widget(object):
    def __init__(self,name):
        self.name = name
        self.already_exist = False
        self.objects = []

    def add_dependency(self,*sub_names):
        if self.already_exist:return
        self.objects = [i for i in sub_names]
        self.already_exist = True

    def build(self):
        print_list = []
        for sub_name in self.objects:
            if not sub_name.objects:
                if sub_name.name not in print_list: print_list.append(sub_name.name)
            else:    
                l = sub_name.build()
                for i in l:
                    if i not in print_list: print_list.append(i)

        if self.name == "All":
            print print_list
        else:
            if self.name not in print_list: print_list.append(self.name)
        return print_list


if __name__ == "__main__":
    luke    = Widget("Luke")
    hansolo = Widget("Han Solo")
    leia    = Widget("Leia")
    yoda    = Widget("Yoda")
    padme   = Widget("Padme Amidala")
    anakin  = Widget("Anakin Skywalker")
    obi     = Widget("Obi-Wan")
    darth   = Widget("Darth Vader")
    _all    = Widget("All")

    luke.add_dependency(hansolo, leia, yoda)
    leia.add_dependency(padme, anakin)
    obi.add_dependency(yoda)
    darth.add_dependency(anakin)

    _all.add_dependency(luke, hansolo, leia, yoda, padme, anakin, obi, darth)
    _all.build()

ממש מסורבל. אפשר הרבה יותר פשוט.

קח את הקוד הישן שלך, ובוא נתחיל עם למחוק את הפקודות שמתיחסות ל already_exists מהפונקציה add כך שנקבל:

class Widget(object):
    def __init__(self,name):
        self.name = name
        self.already_exist = False
        self.objects = []

    def add_dependency(self,*sub_names):
        self.objects = [i for i in sub_names]

עכשיו נמשיך לפונקציה האחרונה-

זה המימוש שאתה כתבת:

    def build(self):
        print_list = []
        for sub_name in self.objects:
            for item in sub_name:
                if item.name not in print_list:
                    print_list.append(item.name)
            if sub_name.name not in print_list:
                print_list.append(sub_name.name)
        print (', '.join(print_list))

אבל הוא בעייתי כי כמו שכתבת הלולאה הפנימית לא עובדת וגם אם היתה עובדת זה לא היה מספיק טוב
(אולי רכיב אחד תלוי ברכיב שני שתלוי בשלישי, ואז צריך שלוש לולאות וכו׳)

יותר טוב להשתמש באותה פונקצית build של הרכיב שיש לך ביד כלומר לכתוב:

    def build(self):
        for sub_name in self.objects:
            sub_name.build()
        print "Ready to build {}".format(self.name)

וזה מתקרב אבל עדיין לא מספיק טוב. הנה פלט לדוגמא של התוכנית:

Ready to build Han Solo
Ready to build Padme Amidala
Ready to build Anakin Skywalker
Ready to build Leia
Ready to build Yoda
Ready to build Luke
Ready to build Han Solo
Ready to build Padme Amidala
Ready to build Anakin Skywalker
Ready to build Leia
Ready to build Yoda
Ready to build Padme Amidala
Ready to build Anakin Skywalker
Ready to build Yoda
Ready to build Obi-Wan
Ready to build Anakin Skywalker
Ready to build Darth Vader
Ready to build All

קל לראות שחלק מהרכיבים נבנו מספר פעמים. אבל אפשר לתקן גם את זה יחסית בקלות: פשוט נסמן על רכיב שבנינו אותו אחרי סיום ה build ואז אם מישהו אחר יפעיל את build שלו הוא יידע לא לבנות את עצמו פעם שניה. זה הקוד המתוקן:

    def build(self):
        if self.already_exist:
            return

        for sub_name in self.objects:
            sub_name.build()

        self.already_exist = True
        print "Ready to build {}".format(self.name)

והפלט:

Ready to build Han Solo
Ready to build Padme Amidala
Ready to build Anakin Skywalker
Ready to build Leia
Ready to build Yoda
Ready to build Luke
Ready to build Obi-Wan
Ready to build Darth Vader
Ready to build All

מקוה שזה עזר ואשמח לסייע אם יש עדיין שאלות עליו

וואי , ממש יפה !
האמת היא שהייתי קרוב אבל לא הבנתי את זה.
כלומר עשיתי כמה נסיונות ואחד מהם (בפונקצית build) היה :

 for sub_name in self.objects:
            sub_name.build()

אך מכיוון שזה לא היה מושלם לא “הגשתי” את זה :slight_smile:

מה שאני למד מכך הוא שגם אם הצלחתי חלק מהתוכנית עדיף להעלות אותה כאן ולהמשיך בעזרתך מאשר להסתבך ולהסתרבל.

ועכשיו לעצם הענין:

  • אני מבין שהשורה ()sub_name.build יוצרת בעצם לולאה/ות נוספת/ות עד להיררכיה הנמוכה ביותר אבל מה שלא הבנתי הוא איך זה שכאשר מגיעים לרכיב שאין לו תת רכיבים הפונקציה יודעת להתמודד עם זה ולשלוח אותו להדפסה? הרי אין כל תנאי שאומר לה לעשות כן ! הייתי מצפה לאיזו שגיאה ולא להמשיך להדפסה כי אנו מניחים שיש לאותו רכיב תת רכיבים ולא היא !

  • בנוסף, כל הרכיבים מלבד הרכיב all הינם תתי רכיבים של all בעוד הוא אינו תת רכיב. לכן מובן לי שכאשר כל תת לולאה מסתיימת היא חוזרת לרכיב האב - שהוא בעצמו תת רכיב - ומדפיסה גם אותו. אבל, all יוצא דופן שכן הוא אינו תת רכיב ולכן אין סיבה להדפיס אותו אלא פשוט לצאת מהלולאה וזהו ! בפועל זה לא קורה אלא גם הוא מודפס למרות שאינו תת רכיב

לכל רכיב יש רשימה של תתי רכיבים. שים לב לפונקציית הבנאי שלך:

    def __init__(self,name):
        self.name = name
        self.already_exist = False
        self.objects = []

במצב שהרשימה ריקה לולאה שרצה עליה פשוט לא עושה כלום (כי אין איברים ברשימה) וכך הכל מסתדר.

הסיבה ש all מודפס זה רק בגלל שממנו התחלנו את הלולאה ואני מזכיר את שתי השורות האחרונות מהתוכנית הראשית:

_all.add_dependency(luke, hansolo, leia, yoda, padme, anakin, obi, darth)
_all.build()

באמת מכל רכיב אחר שהיית מתחיל לא היית מקבל את all

לייק 1

אני נמצא כעת בפרק על חריגים ומנסה להפעיל את הקוד שאתה כתבת ללא הצלחה …

אני מכניס בשורת הפקודה :

3 4

וכלום לא קורה

import sys

while True:
    line = sys.stdin.readline()
    if line == "":break

    (x,y) = [int(n) for n in line.split()]
    print "%d + %d = %d" %(x,y,x+y)

לוחץ Enter אחרי? יכול לשים תמונה?

אני משתמש ב pycharm יש שם שדה edit configuration כדי להכניס נתונים לשורת הפקודה.
בתוכניות קודמות זה עבד מצויין ואילו עכשיו אין פלט.
זה מה שאני מקבל:

ניסיתי להריץ זאת עם שורת פקודה רגילה.
ב Enter הראשון אין כל תוצאה ובפעם השניה זו התוצאה:

טוב, אשמח לקבל תשובה כשתתפנה לזה , בינתיים ניסיתי דרך אחרת:

import sys
import math

def sqrt(x):
    return math.sqrt(x)


a = []
for index,number  in enumerate(sys.argv[1:]):
    try:
        a.append(float(number))
        print sqrt(a[index])
    except ValueError as e:
       print "Please enter numbers > 0 only"
        print e.message

זה עובד מצויין בשורת הפקודה הבאה (משמאל לימין):

4 2  9 81 - 8 - 6 b   n ```

אך כשאני משנה את הסדר משהו משתבש ולא מבצע את החריגים על המספרים השליליים

  ```  4  2   9    81   b    n - 8 - 6 ```

שים לב שהתוכנית השניה עוברת על sys.argv אבל הראשונה על sys.stdin. פרמטרים שמגיעים משורת הפקודה נשמרים ב sys.argv ולא ב sys.stdin ולכן הראשונה לא עבדה לך

ומה לגב התוכנית השניה ?
למה זה עובד לי רק בסדר מסויים?

באמת מעניין.

נסה להוסיף הדפסה על המשתנים בתחילת הלולאה לראות אם מזהה משהו חשוד

נסיתי לדבג את זה.
כאשר אני מכניס את הרשימה הבאה:
6- 8- 81 9 2 4
ובין 81 ל 8 - אני מכניס b n

אני רואה שכל הנתונים (כולל האותיות) נכנסים לרשימה a עד המספר 8 -
כשמגיעים ל 8 - הוא עצמו נכנס לרשימה ואז התוכנית מפסיקה וזורקת הודעת את השגיאה הבאה:

print sqrt(a[index])

IndexError: list index out of range

למה index out of range ?

מדובר על אינדקס מס’ 7 כלומר המס’ 6 -