Módulos y Paquetes en Python PDF

Summary

Este documento describe los módulos y paquetes en Python. Explica cómo organizar código Python en archivos más pequeños llamados módulos. Además, muestra ejemplos de importación y uso de módulos y paquetes.

Full Transcript

Python, por ejemplo Módulos 1 Introducción Los módulos son ficheros que contienen código Python. Un módulo puede incluir funciones, clases y variables, e incluso código ejecutable. Los paquetes son colecciones de módulos agrupados en un directorio. 2 Módulos Los módulos son entidades que permiten...

Python, por ejemplo Módulos 1 Introducción Los módulos son ficheros que contienen código Python. Un módulo puede incluir funciones, clases y variables, e incluso código ejecutable. Los paquetes son colecciones de módulos agrupados en un directorio. 2 Módulos Los módulos son entidades que permiten una organización y división lógica del código con el fin último de su reutilización, así las definiciones de un módulo pueden ser usadas por otros módulos. El uso de módulos permite descomponer grandes programas en ficheros más pequeños y manejables, lo que ofrece entre otras ventajas: Simplicidad: El dividir un problema en partes más sencillas facilita su desarrollo y reduce el número de errores. Mantenimiento: Los módulos que se centran en un dominio determinado tienden a minimizar la interdependencia, lo que reduce la probabilidad de que las modificaciones de un solo módulo tengan un impacto en otras partes del programa. Reutilización: La funcionalidad definida en un módulo puede ser fácilmente reutilizada eliminando la creación de código duplicado. Alcance: Los módulos definen un espacio de nombres separado, lo que ayuda a evitar las colisiones entre los identificadores en diferentes áreas de un programa. Los módulos nos permiten organizar el código en un único fichero.py con código Python. El nombre de módulo es el nombre del fichero sin la extensión. Python tiene multitud de módulos estándar disponibles que se encuentran en el directorio Lib dentro de la ubicación donde se instaló Python. 2.1 Importar antes de usar El contenido de los módulos se puede utilizar en cualquier fichero fuente de Python para hacer uso de su funcionalidad, ejecutando una sentencia de importación previamente. 2.1.1 Declaración import La importación tiene la siguiente sintaxis: import [, ] La referencia a los módulos no incluye la extensión. Es posible abreviar los espacios de nombres mediante un alias, de la forma: import as Cuando el intérprete se encuentra con una declaración de importación, importa el módulo si éste está presente en la ruta de búsqueda. Un módulo puede contener tanto declaraciones ejecutables como definiciones de funciones u otro tipo de objetos. Estas declaraciones están pensadas para inicializar el módulo. Se ejecutan solamente la primera vez que se realiza la importación del módulo. Un módulo se carga una sola vez, independientemente del número de veces que se importe. Esto impide que la ejecución del módulo se repita una y otra vez si se producen múltiples importaciones. Cada módulo tiene su propio espacio de nombres, empleado por todos los objetos definidos en el módulo. De esta forma, las objetos en el módulo no entran en conflicto con los objetos del usuario. Los objetos incluidos en un módulo solo son accesibles si van precedidos por el nombre del módulo al que pertenecen o el alias asignado, de la forma:.. Vamos a crear un módulo con el fichero saludos.py con el siguiente código: saludos.py def hola(): print('Hola Mundo') def hello(): print('Hello World') print('Saludos') Si deseamos usarlo en otro programa debemos hacer primero un import, lo que ya nos permitiría usar las funciones contenidas en el módulo. 1. >>> import saludos 2. Saludos 3. >>> saludos.hola() 4. Hola Mundo 5. >>> saludos.hello() 6. Hello World Al realizar la primera importación se ha ejecutado la sentencia print() que nos visualiza el texto 'Saludos', código que se ejecuta solo una vez en el momento de la importación del módulo. Para hacer uso de las funciones que contiene el módulo debemos emplear el nombre del módulo como prefijo con el operador punto (. ). No siempre vamos a encontrar instalados en el sistema todos los módulos que necesitemos, por eso es conveniente empotrar la sentencia import en un bloque try- except, ya que Python lanza una excepción ImportError cuando no encuentra un módulo, porque no esté instalado o porque no exista un camino de búsqueda que le permita su localización. Así, no está de más hacer: try: import except ImportError: 2.1.2 Declaración from Una variante de la declaración import importa los nombres de un módulo directamente al espacio de nombres del módulo que hace la importación. La sintaxis es: from import [, ] De esta manera es posible importar sólo aquel objeto que vamos a utilizar y evitamos hacer referencia al nombre del módulo. Debe emplearse con cuidado y no se suele recomendar este uso porque puede crear conflictos con variables o con funciones que tengan nombres iguales en otros módulos importados en una misma aplicación. Con el ejemplo del módulo anterior, si solo deseamos emplear una función haríamos: 1. >>> from saludos import hello 2. Saludos 3. >>> hello() 4. Hello World Vemos que al importar con from-import no hemos indicado el prefijo del nombre del módulo desde el que se está importando para hacer uso de la función. De forma alternativa, y poco recomendada, es posible importar todos los nombres de un módulo al espacio de nombres actual. from import * En general se considera una mala práctica el uso del asterisco, ya que sobrecarga nuestro programa (y al intérprete) pues no siempre se van a usar todos los objetos del módulo. No se suele recomendar el uso de from porque puede crear conflictos con objetos que tengan nombres iguales en otros módulos importados o en la misma aplicación. Es mejor listar explícitamente cada importación para identificar de dónde viene cada objeto al hacer uso del espacio de nombres específico. También dificulta la legibilidad de nuestro código, al no tener identificado el origen de los objetos que estemos usando. 2.1.3 Importar en tiempo de ejecución Si se desea importar un módulo en tiempo de ejecución, disponemos de importlib.import_module(). Esta función es útil si los módulos deben cargarse durante la ejecución basándose en nombres de objetos. 1. >>> from importlib import import_module 2. >>> # nombre del paquete y modulo a importar 3. >>> modulo = import_module('paquete.modulo') 4. >>> # llamamos a la función como si hubiéramos hecho un: import paquete.modulo 5. >>> modulo.funcion() 2.1.4 Recargar un módulo El intérprete de Python importa los módulos sólo una vez durante una sesión. Si modificamos uno de nuestros módulos durante el desarrollo de un programa, tendríamos que recargar todo el sistema de desarrollo para disponer de las modificaciones. Una forma de obviar esto pasa por reiniciar el intérprete. Efectivo, pero nada útil. Otra vía pasa por utilizar la función reload(), que vuelve a importar un módulo previamente importado. reload() 2.1.5 Camino de búsqueda de los módulos Para que los módulos estén disponibles para su uso, el intérprete de Python debe ser capaz de localizar el fichero del módulo. Python tiene un conjunto de directorios en los que busca ficheros de módulos. Este conjunto de directorios se denomina ruta de búsqueda, y es análogo a la variable de entorno PATH que utiliza un sistema operativo para localizar un fichero ejecutable. Cuando se importa un módulo, el intérprete busca primero un módulo integrado con ese nombre en el intérprete. Si no lo encuentra, entonces busca un fichero con el nombre del módulo y la extensión.py en una lista de directorios especificada por la variable sys.path, que se inicializa con las siguientes ubicaciones: El directorio actual donde está el programa. PYTHONPATH (una lista de nombres de directorios, con la misma sintaxis que la variable de entorno PATH. El directorio por defecto de la instalación. Podemos ver la lista actual desde el IDLE de Python mediante: 1. >>> import sys 2. >>> sys.path 3. ['', 'C:\\Program Files\\Python311\\Lib\\idlelib', 'C:\\Program Files\\Python311\\pyt Podemos añadir el directorio de nuestra aplicación a la ruta del IDLE con: 1. >>> import sys 2. >>> sys.path.insert(0, r'C:\directorio_aplicacion') En el entorno de Windows, el símbolo Python_Path en el registro de Windows se utiliza para localizar módulos. Y también la variable de entorno Path, como: Path=;C:\\Programs\Python\Python311\Scripts\;C:\ \Programs\Python\Python311\ 2.1.6 Elementos en un módulo La función integrada dir() nos visualiza todos los atributos de un objeto, como una lista de cadenas, lo que nos permite comprobar que métodos nos proporciona un determinado módulo. 1. >>> dir(list) 2. ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__ Aquí vemos tanto las funciones como los atributos asociados al módulo list. En el caso de nuestro módulo saludos: 1. >>> dir(saludos) 2. ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__pa La función dir() sin argumentos produce una lista ordenada alfabéticamente de nombres en la tabla de símbolos locales. 2.2 Módulos y función main() Vamos a ver la forma de trabajar con Python para usar la función de inicio de las aplicaciones, que denominamos main(), como ocurre en otros muchos lenguajes de programación. Los módulos de Python se pueden ejecutar como un guión (script) o incorporados a otros módulos. Vamos a crear un módulo con el fichero modulo_main.py con el siguiente código: modulo_main.py def main(): print('Hola desde main') Si lo ejecutamos directamente, no obtendríamos ningún resultado, ya qué una función solo se ejecuta si la llamamos. Si lo importamos desde otro modulo podremos llamar a la función main(): 1. >>> import modulo_main 2. >>> modulo_main.main() 3. Hola desde main Necesitamos una forma para determinar el contexto de ejecución verificando que es el intérprete de Python el que está ejecutando el guión y no desde una importación. Aquí viene a ayudarnos la forma de trabajar de Python. Cuando se importa un módulo, Python asigna a la variable especial __name__ el nombre del módulo. Sin embargo, si un archivo se ejecuta como un script, el valor de __name__ pasa a contener la cadena '__main__'. De esta manera, podemos discernir en tiempo de ejecución si el archivo es un módulo importado o si se emplea como un guión. Basta con verificar el nombre del módulo en la variable __name__. if __name__ == '__main__': main() Vamos a modificar el fichero modulo_main.py incluyendo un mensaje en la función main() con el valor de la variable especial __name__, con el fin de ver su contenido según la forma en que ejecutemos el fichero. Y en el código que se ejecuta al cargar/llamar el módulo incluiremos la sentencia condicional que hemos comentado, para verificar si se está cargando o ejecutando, y que avisa del arranque y realiza la llamada a la función main() para su ejecución. Según esto, el fichero modulo_main.py quedará de la forma: modulo_main.py def main(): print('Hola desde main') print("En modulo_main.py el valor de __name__ es: ", repr(__name__)) if __name__ == '__main__': print('Arrancando') main() Si lo ejecutamos directamente como un guión, obtendríamos: Arrancando Hola desde main En modulo_main.py el valor de __name__ es: '__main__' Vemos que de esta forma el valor de __name__ es '__main__', lo que hace que se llame a la función main(). Si importamos el módulo, debemos de llamar por nuestra cuenta a la función main() para su ejecución: 1. >>> import modulo_main 2. >>> modulo_main.main() 3. Hola desde main 4. En modulo_main.py el valor de __name__ es: 'modulo_main' En este caso, no aparece el mensaje 'Arrancando', y el valor de __name__ es ahora el nombre del módulo: 'modulo_main'. 2.3 Módulos compilados La carga de un módulo compilado es más rápida. Los ficheros compilados tienen la extensión.pyc y tienen la ventaja de que son independientes de la plataforma, así que la misma biblioteca puede ser compartida a través de sistemas con diferentes arquitecturas. Desde Python 3 no es necesario hacer nada para crear el fichero compilado, que se almacena en la carpeta __pycache__ del proyecto. Siempre que se importa un módulo, Python almacena el código de bytes compilado en ese directorio desde donde lo usará directamente en futuras importaciones. Si la versión compilada está desactualizada, Python la recompila automáticamente antes de importarla. En el caso de distribuciones sin código fuente, donde solo hay una versión compilada, el módulo compilado debe estar en el directorio origen, y no debe existir el módulo fuente. El fichero compilado generalmente contiene el número de versión de Python. En el caso de CPython release 3.8 la versión compilada de un módulo estaría en el directorio __pycache__ como:.cpython-38.pyc Esta convención permite la coexistencia de módulos compilados desde diferentes versiones de Python. 2.4 Módulos estándar Python viene con una biblioteca de módulos estándar. Algunos módulos se integran en el intérprete; estos proveen acceso a operaciones que no son parte del núcleo del lenguaje pero que sin embargo están integrados, tanto por eficiencia como para proveer acceso a primitivas del sistema operativo, como llamadas al sistema. El conjunto de tales módulos es una opción de configuración que también depende de la plataforma subyacente. Python establece unas recomendaciones sobre el uso de los módulos. PEP 8: Import Normalmente los import deben colocarse en líneas distintas. La importación de módulos debe realizarse al comienzo del programa, en orden alfabético de paquetes y módulos, y antes de las variables globales y las constantes del módulo. Las importaciones deben agruparse en el siguiente orden: Módulos propios de Python. Módulos de terceros. Módulos propios. Debe añadirse una línea en blanco después de cada grupo. 3 Paquetes Cuando el número de módulos que desarrollamos crece, se hace preciso establecer un orden, agruparlos por funcionalidad o según la aplicación y los programas donde se usen. Los paquetes permiten una estructuración jerárquica del espacio de nombres de los módulos, evitando colisiones entre los nombres de los módulos. Python emplea la estructura jerárquica de ficheros del sistema operativo para la creación de paquetes. Paquetes Que con la notación de rutas de ficheros: app\modulo1.py app\modulo2.py app\paquete\__init__.py app\paquete\modulo1.py app\paquete\modulo2.py app\paquete\subpaquete\__init__.py app\paquete\subpaquete\modulo3.py Para que un directorio pueda ser considerado un paquete, debe contener un fichero de inicio llamado __init__.py. Este fichero no necesita contener ninguna instrucción, y de hecho, puede estar completamente vacío. Así que, cada directorio que tenga un archivo __init__.py se considera un paquete Python y los subdirectorios que tengan el archivo __init__.py se consideran subpaquetes. 3.1 Importación de paquetes y módulos Al igual que ocurre con los módulos, antes de utilizar cualquier módulo de un paquete es preciso importarlo. 3.1.1 Declaraciones import y from Al importar un módulo que está dentro de un paquete es preciso referenciarlo como paquete.módulo. Cuando queramos importar módulos que están dentro de subpaquetes debemos emplear toda la cadena de nombres de paquetes. La importación de paquetes tiene la siguiente sintaxis: import [.].[, [.]. ] El uso de los objetos del módulo debe llevar también la referencia al paquete:.. Como ocurre con los módulos es posible abreviar los espacios de nombres mediante un alias, de la forma: import. as import.. as La variante de importación con la sentencia from tiene diversas opciones. Importar un objeto de un módulo contenido en un paquete. from. import [, ] Importar un módulo completo de un paquete. from import 3.1.2 Inicialización de paquetes Los paquetes deben llevar un fichero __init__.py en el directorio del paquete. Este fichero se invoca cuando se importa el paquete o un módulo del paquete, por lo que puede utilizarse para la ejecución de código de inicialización de datos a nivel de paquete. Vamos a crear una carpeta a la que denominaremos paquete. En ella pondremos tres ficheros: __init__.py, phello.py y phola.py. paquete\__init__.py paquete\phello.py paquete\phola.py Cada uno de ellos con el contenido siguiente: __init__.py print(f'Hola desde el paquete: {__name__}') phello.py def hello(): print('Hello World') phola.py def hola(): print('Hola Mundo') Cuando importemos el paquete obtendremos: 1. >>> import paquete 2. Hola desde el paquete: paquete Pero si hacemos un dir(), veremos que no aparecen los módulos. Podíamos suponer que Python hubiera cargado todos los módulos del paquete, pero por defecto eso no es lo que sucede. En el caso de los paquetes no se importa nada por defecto. 1. >>> dir(paquete) 2. ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__pa Ahora bien, si importamos cada uno de los módulos con la referencia del paquete, ya si disponemos de los módulos. 1. >>> import paquete.phola, paquete.phello 2. >>> dir(paquete) 3. ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__pa 4. >>> paquete.phola.hola() 5. Hola Mundo 6. >>> paquete.phello.hello() 7. Hello World Pero esto nos obliga a nombrar todos los módulos del paquete, lo que puede resultar pesado y complicado en el caso de muchos módulos. Podemos solucionarlo empleando el formato de carga de la forma: from import * En este caso Python busca el fichero __init__.py en el directorio del paquete, y en él una lista llamada __all__. Si esta lista existe, contendrá la relación de módulos que deben ser cargados. El uso del * para la importación no está recomendado, pero en el caso de los paquetes ofrece una suerte de control sobre los módulos que se pueden cargar inicialmente. Parte, todos o ninguno si no se define la lista __all__. Modificamos el fichero __init__.py, incluyendo la lista __all__ con los paquetes a cargar. __init__.py __all__ = ['phola'] print(f'Hola desde el paquete: {__name__}') Ahora al cargar importando con * vemos que dispondremos del módulo phola, el único incluido en la lista __all__. 1. >>> from paquete import * 2. Hola desde el paquete: paquete 3. >>> dir() 4. ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__ 5. >>> phola.hola() 6. Hola Mundo También podemos definir la lista __all__ en un módulo. En resumen, tanto los paquetes como los módulos utilizan la lista __all__ para controlar lo que se importa cuando se especifica un tipo de importación con *. Pero el comportamiento por defecto difiere: En los paquetes, cuando __all__ no está definido, import * no importa nada. En los módulos, cuando __all__ no está definido, import * importa todo.

Use Quizgecko on...
Browser
Browser