2.19. Modulok írása

Bármely .py fájl egy modul. Ha egy növekvő szkriptet több fájlra osztunk szét, minden fájl rövid marad, és a közös segédfüggvények megoszthatók a szkriptek között.

2.19.1. Egy szkript szétdarabolása

Húzz ki egy összetartozó függvénycsoportot egy saját fájlba:

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

Kimenet:

OpenMV
[ready]

A két fájl egymás mellett helyezkedik el ugyanabban a könyvtárban. Amikor a main.py lefut, az import camera_utils egyszer beolvassa a camera_utils.py fájlt, lefuttatja annak legfelső szintű utasításait, és az eredményül kapott modulobjektumot a main névteren belül a camera_utils névhez köti. Egy második import camera_utils bárhonnan máshonnan ugyanazt az objektumot adja vissza – a modulok az első betöltésük után gyorsítótárba kerülnek.

Egy modul neve a fájlnevéből származik, így a camera_utils.py az import camera_utils formában importálható.

2.19.2. Több fájlos modulok (csomagok)

Egy modul lehet fájlok egy könyvtára is, nem csupán egyetlen .py. A könyvtár neve lesz a modul neve, a benne lévő fájlok pedig annak almoduljai:

camera_utils/
    __init__.py
    text.py
    timing.py

Az __init__.py az a fájl, amely akkor fut le, amikor magát a csomagot importálják; lehet üres, vagy újraexportálhat kiválasztott neveket az almodulokból. Az almodulok pontozott névvel érhetők el:

import camera_utils.text
from camera_utils.timing import elapsed

camera_utils.text.label("ready")

A csomagon belül az almodulok egymást vagy a teljes pontozott névvel, vagy egy relatív importtal érhetik el, amely egy bevezető pontot használ „ez a csomag” jelentéssel:

camera_utils/timing.py

from . import text             # the sibling submodule

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

Ha ehelyett egy konkrét nevet szeretnél behúzni, nevezd meg a pontozott testvér után:

from .text import label

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

A relatív importok önállóvá teszik a csomagot: a csomag könyvtárának átnevezése nem igényli minden almodul szerkesztését.

Akkor használj csomagot, amikor egyetlen fájl kényelmes méreten túl nő, vagy amikor egy összetartozó modulkészlet egy névtér alá tartozik. Hétköznapi szkriptekhez egyetlen .py fájl elég.

2.19.3. A __name__ védelem

Minden modulnak van egy beépített neve, a __name__. Az értéke attól függ, hogyan használják a fájlt:

  • Amikor a fájlt közvetlenül futtatják, a __name__ a "__main__" karakterláncra van állítva.

  • Amikor a fájlt egy másik szkript importálja, a __name__ a modul nevére van állítva – a fájlnévre a .py nélkül.

Az ezt használó idióma a következő:

label_util.py

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

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

Kimenet (közvetlenül futtatva):

[self-test]

Amikor ugyanezt a fájlt ehelyett importálják, a __name__ a modul nevére van állítva, így az if blokk kimarad, és semmi extra nem fut le:

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

Használd ezt a mintát egy gyors füstpróba vagy demó csatolására egy könyvtárfájlhoz, anélkül, hogy zavarnád az azt importáló szkripteket.