2.19. Modules schrijven¶
Elk .py-bestand is een module. Een groeiend script over een paar bestanden verdelen houdt elk bestand kort en laat veelgebruikte helpers tussen scripts gedeeld worden.
2.19.1. Een script opsplitsen¶
Haal een gerelateerde groep functies eruit en zet ze in hun eigen bestand:
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"))
Uitvoer:
OpenMV
[ready]
De twee bestanden staan naast elkaar in dezelfde directory. Wanneer main.py draait, leest import camera_utils één keer camera_utils.py, voert zijn top-level statements uit, en bindt het resulterende module-object aan de naam camera_utils in main. Een tweede import camera_utils van ergens anders geeft hetzelfde object terug – modules worden na hun eerste keer laden gecachet.
De naam van een module komt van zijn bestandsnaam, dus camera_utils.py wordt geïmporteerd als import camera_utils.
2.19.2. Modules over meerdere bestanden (packages)¶
Een module kan ook een directory met bestanden zijn in plaats van één enkele .py. De naam van de directory wordt de modulenaam, en de bestanden erin zijn de submodules:
camera_utils/
__init__.py
text.py
timing.py
__init__.py is het bestand dat draait wanneer de package zelf geïmporteerd wordt; het kan leeg zijn, of het kan geselecteerde namen uit de submodules opnieuw exporteren. De submodules worden bereikt met een naam met punten:
import camera_utils.text
from camera_utils.timing import elapsed
camera_utils.text.label("ready")
Binnen de package kunnen submodules elkaar bereiken via de volledige naam met punten of via een relatieve import die een voorloop-punt gebruikt om “deze package” te betekenen:
camera_utils/timing.py
from . import text # the sibling submodule
def stamp(value):
return text.label(str(value))
Om in plaats daarvan een specifieke naam binnen te halen, noem je hem na de broer of zus met punten:
from .text import label
def stamp(value):
return label(str(value))
Relatieve imports houden een package zelfstandig: het hernoemen van de package-directory vereist niet het bewerken van elke submodule.
Gebruik een package wanneer een enkel bestand voorbij een comfortabele omvang groeit, of wanneer een set gerelateerde modules onder één namespace bij elkaar hoort. Voor alledaagse scripts is een enkel .py-bestand genoeg.
2.19.3. De __name__-bewaker¶
Elke module heeft een built-in naam __name__. De waarde ervan hangt af van hoe het bestand wordt gebruikt:
Wanneer het bestand rechtstreeks wordt gedraaid, wordt
__name__ingesteld op de string"__main__".Wanneer het bestand geïmporteerd wordt door een ander script, wordt
__name__ingesteld op de modulenaam – de bestandsnaam zonder.py.
Het idioom dat hiervan gebruikmaakt is:
label_util.py
def label(text):
return "[" + text + "]"
if __name__ == "__main__":
print(label("self-test"))
Uitvoer (bij rechtstreeks draaien):
[self-test]
Wanneer hetzelfde bestand in plaats daarvan geïmporteerd wordt, wordt __name__ ingesteld op de modulenaam, dus het if-blok wordt overgeslagen en er draait niets extra’s:
>>> import label_util
>>> label_util.__name__
'label_util'
Gebruik dit patroon om een snelle smoke-test of demo aan een bibliotheekbestand te koppelen zonder scripts die het importeren te verstoren.