2.19. כתיבת מודולים¶
כל קובץ .py הוא מודול. פיצול סקריפט גדל בין כמה קבצים שומר על כל קובץ קצר ומאפשר לעוזרים משותפים להיות משותפים בין סקריפטים.
2.19.1. פיצול סקריפט¶
משכו קבוצה קשורה של פונקציות אל קובץ משלהן:
camera_utils.py
def banner():
print("OpenMV")
def label(text):
return "[" + text + "]"
main.py
import camera_utils
camera_utils.banner()
print(camera_utils.label("ready"))
פלט:
OpenMV
[ready]
שני הקבצים יושבים זה לצד זה באותה תיקייה. כאשר main.py רץ, import camera_utils קורא את camera_utils.py פעם אחת, מריץ את משפטיו ברמה העליונה, וקושר את אובייקט המודול המתקבל לשם camera_utils ב-main. import camera_utils שני מכל מקום אחר מחזיר את אותו אובייקט – מודולים נשמרים במטמון לאחר טעינתם הראשונה.
שם של מודול מגיע משם הקובץ שלו, כך ש-camera_utils.py מיובא כ-import camera_utils.
2.19.2. מודולים מרובי-קבצים (חבילות)¶
מודול יכול להיות גם תיקייה של קבצים ולא קובץ .py יחיד. שם התיקייה הופך לשם המודול, והקבצים שבתוכה הם תת-המודולים שלו:
camera_utils/
__init__.py
text.py
timing.py
__init__.py הוא הקובץ שרץ כאשר החבילה עצמה מיובאת; הוא יכול להיות ריק, או שהוא יכול לייצא מחדש שמות נבחרים מתת-המודולים. תת-המודולים מושגים באמצעות שם מנוקד:
import camera_utils.text
from camera_utils.timing import elapsed
camera_utils.text.label("ready")
בתוך החבילה, תת-מודולים יכולים להגיע זה לזה באמצעות השם המנוקד המלא או באמצעות ייבוא יחסי המשתמש בנקודה מובילה כדי לציין ”חבילה זו“:
camera_utils/timing.py
from . import text # the sibling submodule
def stamp(value):
return text.label(str(value))
כדי למשוך שם מסוים במקום זאת, ציינו אותו אחרי האח המנוקד:
from .text import label
def stamp(value):
return label(str(value))
ייבוא יחסי שומר על חבילה עצמאית: שינוי שם תיקיית החבילה אינו דורש עריכה של כל תת-מודול.
השתמשו בחבילה כאשר קובץ יחיד גדל מעבר לגודל נוח, או כאשר קבוצה של מודולים קשורים שייכים יחד תחת מרחב שמות אחד. עבור סקריפטים יומיומיים קובץ .py יחיד מספיק.
2.19.3. מגן ה-__name__¶
לכל מודול יש שם מובנה __name__. ערכו תלוי באופן שבו הקובץ נמצא בשימוש:
כאשר הקובץ רץ ישירות,
__name__מוגדר למחרוזת"__main__".כאשר הקובץ מיובא על ידי סקריפט אחר,
__name__מוגדר לשם המודול – שם הקובץ ללא.py.
הניב המשתמש בכך הוא:
label_util.py
def label(text):
return "[" + text + "]"
if __name__ == "__main__":
print(label("self-test"))
פלט (כאשר רץ ישירות):
[self-test]
כאשר אותו קובץ מיובא במקום זאת, __name__ מוגדר לשם המודול, כך שבלוק ה-if מדולג ושום דבר נוסף אינו רץ:
>>> import label_util
>>> label_util.__name__
'label_util'
השתמשו בדפוס כדי לצרף בדיקת עשן או הדגמה מהירה לקובץ ספרייה מבלי להפריע לסקריפטים שמייבאים אותו.