מה זה __name__ == __main__ בפייתון?
למה להשתמש בתנאי __name__ == "__main__"? התשובה הקצרה היא ששימוש בתנאי בתוך סקריפט מאפשר להריץ קוד רק כאשר מריצים את הסקריפט ישירות ולא כשמייבאים מודול.
לאחר שענינו בקצרה ניגש לתשובה המפורטת שתסביר מה זה __name__, מה זה מודול, מה זה "__main__", ותפרט סיבות לשימוש.
מה זה מודול של פייתון?
מודול הוא יחידה מובחנת של קוד שנמצאת בתוך קובץ נפרד. בתוך מודול אפשר להגדיר פונקציות, קלאסים, משתנים. את קוד המודול אפשר להריץ ישירות או בעקיפין באמצעות ייבוא המודול לתוך מודול אחר.
מה זה __name__ ומה זה "__main__"?
משתנה הקסם של פייתון ששמו __name__ הוא משתנה מיוחד שערכו תלוי בהקשר.
כדי להבין את זה נפתח שני קבצים בתוך תיקייה אחת:
- my_script.py
- my_module.py
נפתח את הסקריפט הראשון, my_script.py , ונכתוב בתוכו:
print(__name__)
נריץ את הסקריפט מהטרמינל:
$ python my_script.py
התוצאה:
__main__
נפתח את הסקריפט השני, my_module.py ונכתוב לתוכו את הקוד:
print(__name__)
נריץ את הסקריפט מהטרמינל:
$ python my_module.py
התוצאה:
__main__
המסקנה: השם __name__ של הסקריפט הנוכחי שאנחנו מריצים הוא "__main__".
השם שונה מ-"__main__" כאשר מייבאים את המודול במקום להריץ אותו באופן ישיר. כדי להבין את זה נייבא את my_module לתוך my_script ונשנה את הקוד בתוכו ככתוב להלן:
my_script.py
import my_module
print(f"Imported script name: {my_module.__name__}")
print(f"Current running script name: {__name__}")
נריץ :
$ python my_script.py
התוצאה:
my_module
Imported script name: my_module
Current running script name: __main__
על מסך הטרמינל הודפסו 3 שורות. נסביר אותם:
-
השורה הראשונה הדפיסה את השם "my_module" שהוא תוצאה של הרצת:
print(__name__)
בתוך המודול המיובא. השם אינו "__main__" אלא שם הקובץ ללא סיומת ".py" כי הערך של __name__ כאשר מייבאים מודול היא שם הסקריפט ללא הסיומת.
-
השורה השנייה מדפיסה :
Imported script name: my_module
זו תוצאה של הדפסת המשתנה __name__ עבור המודול המיובא. השם של המודול המיובא בתוך המודול המייבא הוא שם הקובץ המיובא ללא הסיומת ".py" כפי שראינו בסעיף 1.
-
השורה השלישית מדפיסה:
Current running script name: __main__
"__main__" כיוון שזה השם __name__ של הסקריפט אותו אנו מריצים ישירות בקונסולה.
לסיכום, __name__ הוא שם הסקריפט והשם הזה תלוי בהקשר. השם של הסקריפט הנוכחי אותו אנו מריצים הוא "__main__" ושמו של המודול המיובא הוא כשם הסקריפט המיובא ללא סיומת ".py"
למה להשתמש בתנאי __name__ == "__main__"
בדוגמה הקודמת ראינו שהמודול המיובא ביצע פונקציה באופן אוטומטי בלי שהוא נדרש לכך על ידי הסקריפט המייבא. זו התנהגות לא רצויה עם השלכות בלתי צפויות מבחינת הקוד אותו אנו מריצים באופן ישיר. אז מה שאפשר לעשות כדי למנוע את ההתנהגות הבלתי רצויה של המודול המיובא הוא להסתיר את הקוד במודול המיובא מתחת לתנאי.
נערוך את המודול המיובא כדי שהקוד שמדפיס את השם יודפס אך ורק תחת התנאי:
my_module.py
def print_name():
print(f"my_module's name is {__name__}")
if __name__ == "__main__":
print_name()
את הקוד להדפסת ההודעה שמנו בתוך פונקציה print_name(). את הקריאה לפונקציה שמנו תחת התנאי __name__ == "__main__".
נריץ את הסקריפט my_module ישירות מהטרמינל:
$ python my_module.py
כיוון שהרצנו את my_module ישירות, ולא באופן עקיף על ידי יבוא, התנאי יתקיים, הקוד יבוצע, והתוצאה:
my_module's name is __main__
עכשיו נריץ את הסקריפט my_script שמייבא את my_module:
$ python my_script.py
התוצאה:
Imported script name: my_module
Current running script name: __main__
הקוד אותו שמנו תחת התנאי __name__ == "__main__" במודול המיובא לא בוצע כיוון שלא הרצנו אותו באופן ישיר.
זה לא אומר שאי אפשר להריץ את הפונקציה print_name() גם מהמודול המייבא.
נערוך את המודול המייבא כדי שיפעיל את הפונקציה print_name() על ידי כך שייקרא לה באופן מפורש מתוך המודול המיובא:
my_script.py
import my_module
my_module.print_name()
print(f"Imported script name: {my_module.__name__}")
print(f"Current running script name: {__name__}")
בשורה הראשונה ייבאנו את המודול my_module. בשורה השנייה הפעלנו את הפונקציה print_name() מתוך המודול באמצעות שורת הקוד:
my_module.print_name()
נריץ:
$ python my_script.py
התוצאה בקונסולה:
my_module's name is my_module
Imported script name: my_module
Current running script name: __main__
- השורה הראשונה שהודפסה לקונסולה היא תוצאה של הרצת הפונקציה "print_name()" לה קראנו באופן מפורש מהמודול המייבא.
נסכם, מאחר ששמנו את הקריאה לפונקציה תחת התנאי __name__ == "__main__" כשלא קראנו לה באופן מפורש מתוך הקובץ המייבא הפונקציה לא פעלה אבל כשכן קראנו לה היא פעלה. המשמעות היא שיש לנו שליטה בהתנהגות המודולים אותם אנו מייבאים לתוך הסקריפט אותו אנו מריצים.
למה חשוב להשתמש בתנאי __name__ == "__main__"?
ראינו שמה שנמצא מתחת לתנאי יוצא אל הפועל רק כאשר מריצים את המודול ישירות או קוראים באופן מפורש לפונקציה בתוך המודול המייבא זו התנהגות שמאפשרת לנו להימנע מתופעות לא רצויות כשאנחנו עובדים עם מודולים חיצוניים, ומצד שני, כשאנחנו מריצים ישירות את המודול לקבל את ההתנהגות המוגדרת מתחת לתנאי.
סיבות נוספות לעבוד עם התנאי הנגזרות ממה שאמרנו הם:
- מניעת הרצה אוטומטית של מודולים מיובאים ללא שנדרשו לכך באופן מפורש מתוך המודול המייבא אותו אנו מריצים באופן ישיר.
- כיוון שערך משתנה הקסם __name__ הוא "__main__" רק כאשר מריצים את המודול באופן ישיר מתקיים התנאי __name__ == "__main__" דבר המסייע לנו להבין איזה חלק של הקוד אותו קיבלנו מיועד לרוץ באופן ישיר.
- מקל על בדיקת המודולים כיחידה נפרדת בזמן הפיתוח כי את קוד הבדיקה אפשר לשים תחת התנאי __name__ == "__main__" בכל מודול שרוצים לבחון.
- מאפשר קבלת התנהגות שונה כאשר מריצים את הקוד כמודול נפרד או כשמייבאים אותו מה שמקל על יישום מודולים. החשיבות של עבודה עם מודולים נפרדים היא תרומתה לסביבה מודולורית כאשר באותו המודול יכולים להשתמש במסגרת פרויקטים שונים.
לסיכום, השימוש בתנאי __name__ == "__main__" מספק דרך להבדיל בין הסקריפט המופעל ישירות לבין סקריפט המיובא כמודול. השימוש בתנאי עוזר לשלוט על זרימת הביצוע, בהפרדת קוד לשימוש חוזר מקוד ספציפי לתוכנית הראשי, מניעת ביצוע לא רצוי והקלה על בדיקות יחידה ואיתור באגים.
מדריכים נוספים בסדרה ללימוד פייתון
ארבעת התחומים (scope) של פייתון
בדיקות יחידה unit test בפייתון באמצעות pytest
לכל המדריכים בסדרה ללימוד פייתון
אהבתם? לא אהבתם? דרגו!
0 הצבעות, ממוצע 0 מתוך 5 כוכבים
המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.
למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.
שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.
המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?
השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.