Menu

*args ו-**kwargs ב-Python: ארגומנטים פוזיציונליים וארגומנטים בעלי שם

מה המשמעות של *args ו-**kwargs, מתי להשתמש בהם ואיך להעביר ארגומנטים בצורה נקייה מפונקציה לפונקציה.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

כשלא יודעים כמה ארגומנטים יגיעו

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

Python פותרת את זה בעזרת שני סימנים מיוחדים ברשימת הפרמטרים: *args ו-**kwargs.

*args אוסף ארגומנטים פוזיציונליים

כוכבית אחת אומרת "ארזו את כל הארגומנטים הפוזיציונליים העודפים לתוך tuple":

בתוך הפונקציה, args הוא tuple רגיל. אפשר לעבור עליו בלולאה, לגשת אליו לפי אינדקס, להעביר אותו ל-len() או לחתוך אותו.

*args מופיע בדרך כלל לצד פרמטרים בעלי שם:

first תופס את הארגומנט הראשון; *rest אורז את כל מה שבא אחריו לתוך tuple.

**kwargs אוסף ארגומנטים בעלי שם

שתי כוכביות עושות את אותו הדבר עבור ארגומנטים בעלי שם, ואורזות אותם לתוך dict:

בתוך describe, kwargs הוא dict רגיל. המפתחות הם שמות הארגומנטים, בתור מחרוזות.

שימוש בשניהם יחד

אפשר להשתמש בשניהם באותה פונקציה. המוסכמה היא *args לפני **kwargs:

הסדר המלא של הפרמטרים, מההתחלה ועד הסוף, הוא:

  1. פרמטרים פוזיציונליים רגילים (חובה או עם ערכי ברירת מחדל).
  2. *args.
  3. פרמטרים שמקבלים ערך רק לפי שם (כל מה שבא אחרי *args חייב לעבור לפי שם).
  4. **kwargs.

title תופס את הארגומנט הפוזיציונלי הראשון. שאר הפוזיציונליים נכנסים ל-tags. את draft חייבים להעביר לפי שם (הוא מופיע אחרי *tags). כל ארגומנט בעל שם אחר נוחת ב-metadata.

פריסה עם * ו-** בנקודת הקריאה

הכוכביות עובדות גם בכיוון ההפוך: הן פורסות רצף או dict לתוך הארגומנטים של קריאה:

זה שימושי מאוד להעברת ארגומנטים הלאה:

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

מתי *args ו-**kwargs הם בחירה לא נכונה

קל להתלהב ולהשתמש בהם בכל מקום. שתי אזהרות:

הם מסתירים מה הפונקציה מצפה לקבל

אם כל פונקציה בקוד שלכם היא def f(*args, **kwargs), לקוד שקורא לה אין מושג אילו ארגומנטים תקינים. השתמשו בפרמטרים בעלי שם בכל פעם שאפשר, ותנו ל-*args/**kwargs לשאת רק קלט שבאמת משתנה במספרו, או העברה נקייה הלאה.

הודעות השגיאה נעשות מעורפלות

שם ארגומנט עם שגיאת כתיב הופך ל-None שקט או ל-KeyError עמוק בתוך הפונקציה, במקום הודעת "unexpected keyword argument" מיידית בנקודת הקריאה. פרמטרים בעלי שם נותנים משוב טוב בהרבה.

כלל אצבע: העדיפו פרמטרים בעלי שם כברירת מחדל, והשתמשו ב-*args/**kwargs רק כשהפונקציה באמת גמישה או כשהיא מעבירה ארגומנטים לפונקציה אחרת.

דוגמה מעשית קטנה

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

*values מאפשר לקורא להעביר כל מספר של פריטים; **style בולע הגדרות נוספות בלי לחייב שכל אפשרות תהיה פרמטר בעל שם. זה גמיש בלי להיות אטום, כי הלוגיקה הפנימית מראה בדיוק אילו מפתחות היא קוראת מתוך style.

סיכום

  • *args אורז ארגומנטים פוזיציונליים עודפים לתוך tuple.
  • **kwargs אורז ארגומנטים בעלי שם עודפים לתוך dict.
  • בנקודת הקריאה, *seq ו-**dict פורסים בכיוון ההפוך.
  • הפרמטרים חייבים להופיע בסדר הזה: רגילים → *args → רק לפי שם → **kwargs.
  • אל תגזימו: פרמטרים בעלי שם ברורים יותר כשאפשר להשתמש בהם.

בהמשך: lambda, דרך לכתוב פונקציות קטנות וחד-פעמיות בשורה אחת.

שאלות נפוצות

מה זה *args ב-Python?

*args אוסף את כל הארגומנטים הפוזיציונליים העודפים לתוך tuple. def f(*args): מאפשר לקרוא ל-f(1, 2, 3) ולקבל את args בתור (1, 2, 3). השם args הוא מוסכמה: אפשר לקרוא לו בכל שם, אבל כולם משתמשים ב-*args.

מה זה **kwargs ב-Python?

**kwargs אוסף את כל הארגומנטים בעלי השם העודפים לתוך dict. def f(**kwargs): מאפשר לקרוא ל-f(name='Ada', age=30) ולקבל את kwargs בתור {'name': 'Ada', 'age': 30}. יחד, *args ו-**kwargs מאפשרים לפונקציה לקבל כל שילוב של ארגומנטים.

האם חייבים לקרוא להם args ו-kwargs?

לא, הכוכביות הן מה שחשוב, לא השמות. *values ו-**options עובדים בדיוק אותו דבר. אבל args ו-kwargs הם מוסכמה כמעט אוניברסלית בקוד Python, אז כדאי להיצמד אליהם אלא אם יש סיבה ספציפית לבחור שם תיאורי יותר.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל