לדלג לתוכן

מדריך ל-argparse - ארגומנטים לתוכנת פייתון

בואו נדבר בכנות. כתבתם סקריפט פייתון שמעבד קובץ, ובראש הקוד יש לכם שורה כמו filename = "data.csv". עובד מצוין, עד שבפעם הבאה אתם רוצים להריץ אותו על קובץ אחר, ואתם נכנסים לקוד לשנות את השורה הזאת ידנית. זה בזבוז זמן מטופש, וזה בדיוק הבעיה ש-argparse פותר - הוא נותן לכם להעביר ערכים לתוכנית ישירות משורת הפקודה, בלי לגעת בקוד בכלל.

למה לא פשוט לקבע ערכים בקוד

הקבעה של ערכים בתוך הקוד (hardcoding) עובדת נהדר בזמן פיתוח, אבל היא הופכת כל סקריפט לכלי חד-פעמי שרק אתם יכולים להפעיל, ורק בדרך אחת. ברגע שתרצו להריץ את אותו סקריפט על קובץ אחר, עם הגדרות אחרות, או שתרצו לתת אותו למישהו אחר להריץ, תגלו שהוא לא גמיש בכלל. תוכנית שורת פקודה טובה מקבלת את הפרמטרים שלה כארגומנטים, בדיוק כמו שפקודות כמו ls או git מקבלות.

ההתחלה - ArgumentParser בסיסי

argparse הוא מודול מובנה בפייתון, אין צורך להתקין כלום. הבסיס הוא ליצור אובייקט ArgumentParser ולהוסיף לו ארגומנטים:

import argparse

parser = argparse.ArgumentParser(description="תוכנית לעיבוד קובץ")
parser.add_argument("filename")

args = parser.parse_args()
print(args.filename)

אם תשמרו את זה כקובץ בשם script.py ותריצו python script.py data.csv, הערך data.csv ייכנס אוטומטית ל-args.filename. זה נקרא ארגומנט פוזיציוני (positional) - חובה להעביר אותו, והוא מזוהה לפי המיקום שלו בשורה, לא לפי שם.

ארגומנטים אופציונליים ודגלים

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

parser.add_argument("--output", default="result.txt", help="שם קובץ הפלט")
parser.add_argument("--verbose", action="store_true", help="הדפסת מידע מפורט")

--output הוא ארגומנט עם ערך - אם לא מציינים אותו, הוא מקבל את ברירת המחדל result.txt. --verbose הוא דגל (flag) בלי ערך - action="store_true" אומר שאם הדגל מופיע, args.verbose יהיה True, ואם לא, הוא יהיה False כברירת מחדל. אין צורך לכתוב --verbose True, מספיק לכתוב --verbose.

דוגמה מלאה שעובדת

בואו נחבר הכל לסקריפט אמיתי - תוכנית שסופרת שורות בקובץ, עם אפשרות לפלט מפורט:

import argparse
from pathlib import Path

parser = argparse.ArgumentParser(description="סופר שורות בקובץ טקסט")
parser.add_argument("filename", help="הקובץ לספירה")
parser.add_argument("--output", default=None, help="קובץ לשמירת התוצאה")
parser.add_argument("--verbose", action="store_true", help="הדפסת פרטים נוספים")

args = parser.parse_args()

path = Path(args.filename)
if not path.exists():
    print(f"הקובץ {args.filename} לא נמצא")
else:
    lines = path.read_text(encoding="utf-8").splitlines()
    count = len(lines)

    if args.verbose:
        print(f"נבדק הקובץ: {path}")
        print(f"מספר שורות שנמצאו: {count}")
    else:
        print(count)

    if args.output:
        Path(args.output).write_text(str(count), encoding="utf-8")

עכשיו אפשר להריץ את זה בכמה דרכים שונות, בלי לגעת בקוד:

python count_lines.py data.txt
python count_lines.py data.txt --verbose
python count_lines.py data.txt --output result.txt --verbose

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

עזרה אוטומטית בחינם

אחד היתרונות הנחמדים ביותר של argparse הוא שהוא בונה לכם הודעת עזרה אוטומטית, בלי שתצטרכו לכתוב אותה בעצמכם:

python count_lines.py --help

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

טיפוסים וערכים מוגבלים

argparse לא רק קולט טקסט - אפשר לבקש ממנו להמיר ארגומנט לטיפוס מסוים באופן אוטומטי, ואפילו להגביל אותו לרשימת ערכים חוקיים:

parser.add_argument("--repeat", type=int, default=1, help="כמה פעמים לחזור על הפעולה")
parser.add_argument(
    "--mode",
    choices=["fast", "slow"],
    default="fast",
    help="מצב ריצה",
)

args = parser.parse_args()
print(args.repeat * 2)  # args.repeat כבר מספר שלם, לא מחרוזת

עם type=int, אם מישהו יעביר --repeat abc, argparse יעצור מיד עם הודעת שגיאה ברורה, במקום שהתוכנית תיפול מאוחר יותר עם שגיאת טיפוס מבלבלת. ועם choices, אם יעבירו ערך שלא ברשימה המותרת, יתקבל הסבר מדויק אילו ערכים כן חוקיים. שני אלה חוסכים המון קוד ולידציה שהייתם צריכים לכתוב בעצמכם.

מתי זה שווה את המאמץ

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

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

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

הצטרפו לקהילה בדיסקורד