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'
השתמשו בדפוס כדי לצרף בדיקת עשן או הדגמה מהירה לקובץ ספרייה מבלי להפריע לסקריפטים שמייבאים אותו.