2.19. Scrierea modulelor

Orice fișier .py este un modul. Împărțirea unui script în creștere pe câteva fișiere menține fiecare fișier scurt și permite ca funcțiile ajutătoare comune să fie partajate între scripturi.

2.19.1. Împărțirea unui script

Scoate un grup înrudit de funcții într-un fișier propriu:

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"))

Ieșire:

OpenMV
[ready]

Cele două fișiere stau unul lângă altul în același director. Când main.py rulează, import camera_utils citește camera_utils.py o singură dată, execută instrucțiunile sale de nivel superior și leagă obiectul modul rezultat de numele camera_utils în main. Un al doilea import camera_utils de oriunde altundeva returnează același obiect – modulele sunt stocate în cache după prima lor încărcare.

Numele unui modul provine din numele fișierului său, așa că camera_utils.py este importat ca import camera_utils.

2.19.2. Module cu mai multe fișiere (pachete)

Un modul poate fi, de asemenea, un director de fișiere, în loc de un singur .py. Numele directorului devine numele modulului, iar fișierele din interior sunt submodulele sale:

camera_utils/
    __init__.py
    text.py
    timing.py

__init__.py este fișierul care rulează atunci când pachetul în sine este importat; poate fi gol sau poate re-exporta nume selectate din submodule. Submodulele sunt accesate cu un nume cu punct:

import camera_utils.text
from camera_utils.timing import elapsed

camera_utils.text.label("ready")

În interiorul pachetului, submodulele se pot accesa reciproc fie prin numele complet cu punct, fie printr-un import relativ care folosește un punct inițial pentru a însemna „acest pachet”:

camera_utils/timing.py

from . import text             # the sibling submodule

def stamp(value):
    return text.label(str(value))

Pentru a aduce în schimb un nume specific, denumește-l după elementul-frate cu punct:

from .text import label

def stamp(value):
    return label(str(value))

Importurile relative mențin un pachet autonom: redenumirea directorului pachetului nu necesită editarea fiecărui submodul.

Folosește un pachet atunci când un singur fișier crește peste o dimensiune comodă sau când un set de module înrudite își are locul împreună sub un singur spațiu de nume. Pentru scripturile de zi cu zi, un singur fișier .py este suficient.

2.19.3. Garda __name__

Fiecare modul are un nume încorporat __name__. Valoarea sa depinde de modul în care este folosit fișierul:

  • Când fișierul este rulat direct, __name__ este setat la șirul "__main__".

  • Când fișierul este importat de un alt script, __name__ este setat la numele modulului – numele fișierului fără .py.

Expresia idiomatică care folosește acest lucru este:

label_util.py

def label(text):
    return "[" + text + "]"

if __name__ == "__main__":
    print(label("self-test"))

Ieșire (când este rulat direct):

[self-test]

Când același fișier este importat în schimb, __name__ este setat la numele modulului, deci blocul if este sărit și nu rulează nimic în plus:

>>> import label_util
>>> label_util.__name__
'label_util'

Folosește acest tipar pentru a atașa un test rapid de verificare sau o demonstrație la un fișier de bibliotecă, fără a deranja scripturile care îl importă.