2.19. Escribir módulos¶
Cualquier archivo .py es un módulo. Repartir un script en crecimiento entre varios archivos mantiene cada archivo corto y permite compartir los ayudantes comunes entre scripts.
2.19.1. Dividir un script¶
Saca un grupo de funciones relacionadas a su propio archivo:
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"))
Salida:
OpenMV
[ready]
Los dos archivos conviven uno junto al otro en el mismo directorio. Cuando se ejecuta main.py, import camera_utils lee camera_utils.py una vez, ejecuta sus sentencias de nivel superior y enlaza el objeto módulo resultante al nombre camera_utils en main. Un segundo import camera_utils desde cualquier otro sitio devuelve el mismo objeto: los módulos se almacenan en caché tras su primera carga.
El nombre de un módulo procede de su nombre de archivo, así que camera_utils.py se importa como import camera_utils.
2.19.2. Módulos de varios archivos (paquetes)¶
Un módulo también puede ser un directorio de archivos en lugar de un único .py. El nombre del directorio pasa a ser el nombre del módulo, y los archivos de su interior son sus submódulos:
camera_utils/
__init__.py
text.py
timing.py
__init__.py es el archivo que se ejecuta cuando se importa el propio paquete; puede estar vacío, o puede reexportar nombres seleccionados de los submódulos. A los submódulos se accede con un nombre con puntos:
import camera_utils.text
from camera_utils.timing import elapsed
camera_utils.text.label("ready")
Dentro del paquete, los submódulos pueden acceder entre sí ya sea por el nombre completo con puntos o mediante una importación relativa que usa un punto inicial para referirse a «este paquete»:
camera_utils/timing.py:
from . import text # the sibling submodule
def stamp(value):
return text.label(str(value))
Para incorporar un nombre concreto en su lugar, indícalo tras el hermano con puntos:
from .text import label
def stamp(value):
return label(str(value))
Las importaciones relativas mantienen un paquete autocontenido: renombrar el directorio del paquete no obliga a editar todos los submódulos.
Usa un paquete cuando un solo archivo supere un tamaño cómodo, o cuando un conjunto de módulos relacionados deba agruparse bajo un mismo espacio de nombres. Para los scripts cotidianos, un único archivo .py es suficiente.
2.19.3. La protección __name__¶
Todo módulo tiene un nombre integrado __name__. Su valor depende de cómo se esté usando el archivo:
Cuando el archivo se ejecuta directamente,
__name__toma el valor de la cadena"__main__".Cuando el archivo es importado por otro script,
__name__toma el valor del nombre del módulo: el nombre de archivo sin.py.
El modismo que aprovecha esto es:
label_util.py:
def label(text):
return "[" + text + "]"
if __name__ == "__main__":
print(label("self-test"))
Salida (al ejecutarse directamente):
[self-test]
Cuando el mismo archivo se importa en cambio, __name__ toma el valor del nombre del módulo, por lo que el bloque if se omite y no se ejecuta nada adicional:
>>> import label_util
>>> label_util.__name__
'label_util'
Usa este patrón para añadir una prueba rápida de verificación o una demostración a un archivo de biblioteca sin molestar a los scripts que lo importan.