מנסה להבין - פונקציה get מחברת 2

לא ממש מצליחה להבין מה קורה בפונקציה.
def get(dictionary, *args, **kwargs):
return dictionary.get(*args, **kwargs)

למה משמשים ה-kwargs? מתי משתמשים בזה?

אני אצטרך מיקוד לגבי איפה הבעיה. הצלחת להבין מה ** עושה בגדול בכותרת של הגדרת הפונקציה?

בגדול - כן.
בקטן - לא הבנתי מה מטרת הפונקציה כל כך.

הפונקציה מחקה את פונקציית get של dictionary

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

אין צורך להתנצל, נסביר כמה שצריך :slight_smile:

ספציפית הפונקציה get יכולה לקבל גם פרמטר נוסף, default value, שיחזור אם ה־key לא קיים במילון.
היתרון של *args, **kwargs הוא שלא כ"כ אכפת לנו אילו פרמטרים יועברו לפונקציה “המקורית”, ואנחנו לא באמת צריכים לדעת את החתימה שלה.

אפשר לחקות ככה כל פונקציה:

def my_range(*args, **kwargs):
    return range(*args, **kwargs)
def open_sesame(*args, **kwargs):
    return open(*args, **kwargs)

תודה, את הרעיון שאפשר לחקות פונקציה הבנתי.
אם יש לך עוד קצת סבלנות - מסקרן אותי למה הפונקציה get המקורית יכולה\צריכה לקבל יותר מערך אחד - גם בערכים שהיא אמורה לבדוק, וגם בערך ברירת המחדל.
שוב תודה רבה

לייק 1

אם אנחנו מדברים ספציפית על get, היא יודעת לקבל פרמטר נוסף (שיכנס לתוך args במקרה שלנו) שיחזיר ערך במידה והערך הדיפולטי לא קיים. לכן, כשאני בא לחקות אותה, אני שם *args כי אני לא יודע כמה פרמטרים אני הולך לקבל.
יכול להיות גם שמתישהו פייתון תשכלל קצת את הפונקציה get, וסתם לדוגמה, יהיה פרמטר שנקרא fail_safe ויהיה אפשר להעביר אליו False אם אנחנו רוצים שיקפוץ KeyError ברגע שהמפתח שחיפשנו לא קיים.
זאת אומרת שבמצב התיאורטי הזה יוכלו לקרוא לה בכל אחת מהצורות הבאות:

d.get('key')
d.get('key', 'missing value)
d.get('key', fail_safe=False)

במקרה הזה, החיקוי שלנו עדיין יעבוד – כי כתבנו שם **kwargs והפונקציה שלנו יודעת להתמודד גם עם ערכים שמועברים לפי שם.

אני מצטערת, אבל עדיין לא מבינה למה צריך גם args וגם kwargs. מה כל אחד מהם נותן?
משהו פה ממש לא מובן לי.

אולי כדאי לנסות לעבור שוב על המחברת? :slight_smile:
*args הוא זה שאליו יתקבצו הפרמטרים שנשלחים לפונקציה לפי מיקום.
**kwargs הוא זה שאליו יתקבצו הפרמטרים שנשלחים לפונקציה לפי שם.

אז אם נכתוב את זה:

def get(d, *args, **kwargs):
    return d.get(*args, **kwargs)

get(d, 'key')
get(d, 'key', 'missing value')
get(d, 'key', fail_safe=False)

בכל הדוגמאות הללו 'key' ילך ל־args.
בשורה לפני־האחרונה, גם missing_value ילך ל־args.
בשורה האחרונה, ב־args יהיה ‘key’ כאיבר בודד ב־tuple, וב־kwargs יווצר המילון {'fail_safe': False}

אם זה עדיין לא מובן אני אצטרך שתעזרי לי למצוא את הנקודה שאת מרגישה שלא ברורה לך :slight_smile:

2 לייקים

כנראה לא הסברתי את עצמי כראוי.
אני מבינה בכללי את המשמעות של ערך עם כוכבית או עם שתי כוכביות, אבל למיטב הבנתי הפונקציה get המקורית מקבלת במקסימום שני ערכים - ערך אחד שהוא המפתח (שלפיו מקבלים ערך מהמילון) ועוד ערך של ברירת מחדל, שהוא אופציונלי.
אני לא מבינה למה הפונקציה הזו כתוב כמו שהיא כתובה, ולא פשוט משהו כמו:
get(key, default)
באלו מקרים הפונקציה הזו תקבל יותר משני פרמטרים? באלו מקרים השימוש בה יצדיק את הערכים הרבים?

מקווה שעכשיו אני ברורה יותר

אם נעשה def get(key, default) אז default לא יהיה ערך דיפולטי, ונהיה חייבים להעביר אותו בכל פעם.
מעבר לזה – get בגדול, כרגע, כמו שהיא ממומשת עכשיו בפייתון, לא מקבלת פרמטרים נוספים.
אבל אם היא יום אחד כן תורחב, וכן יהיה אפשר להעביר פרמטרים נוספים – אני רוצה שהחיקוי הזול שלי יתפוס גם להרחבה הזו – ולכן אני שם את *args ואת **kwargs

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

הבנתי.
אז זו כנראה התשובה - הכנה להרחבה עתידית…
תודה :slight_smile:

לייק 1

זאת בגדול השאלה שלי.

אם יש לך דוגמה טובה יותר – אשמח לשמוע :slight_smile:

כמובן שאין לי… מניחה שיצוצו כשנתקדם, סתם מציינת שלפעמים דווקא קל יותר להבין איך להשתמש בכלים חזקים כשממש צריך. וחוץ מזה, לקח לי הרבה זמן להבין למה המרצה ההוא התכוון, וזה משהו שאני זוכרת (הרבה) שנים אחרי אז חשבתי שאחלוק :wink:

יש לי שאלה אחרת - מאוד כללית, ולא ממש קשורה לעיל (אולי קצת, בעצם). אם אני רוצה להכין רשימה, שתחלק את איבריה לפונקציה , זה עובד לי טוב אם משתני הפונקציה הם מסוג מסוים, אבל לא כ’כ אם יש קריאה בשם לחלק מהמשתנים בפונקציה, כלומר, עבור רשימה של טאפלים ‘פשוטים’, : (1, 2, 3) עובד לי אחלה. אבל אם הפונקציה לוקחת יותר משהו כמו: (1, 2, arg=5) אני לא מצליחה להכין את רשימת הדוגמאות. השגיאה שאני מקבלת לא ברורה לי לגמרי, אבל נראה שמקורה בסימן =. אז איך עושים את זה?

משתנים שבאים אחרי **kwargs מחייבים שתעבירי אותם לפי שם, ולא לפי מיקום. זה בלתי אפשרי כשמדובר ברשימה. יתכן שזה המצב.

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

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