Módulos y Paquetes de Python

Este documento explora el concepto de módulos y paquetes en Python, dos elementos fundamentales que permiten organizar y reutilizar el código de manera eficiente. A través de ejemplos y explicaciones claras, se abordarán las diferencias entre módulos y paquetes, así como su creación y uso en proyectos de programación.

Módulos y Paquetes de Python
Módulos y Paquetes de Python

¿Qué es un Paquete y un Módulo?

Paquete

Un paquete es una colección de módulos organizados dentro de un directorio. Este directorio debe incluir un archivo especial llamado __init__.py, que indica a Python que el directorio es un paquete, Si no se necesita lógica específica, el archivo puede estar vacío. Esto es suficiente para que Python trate al directorio como un paquete. pero es buena práctica incluir un docstring que describa el propósito general del paquete. Ejemplo:

                  
                    """
                    Paquete: operaciones_matematicas
                    Este paquete incluye módulos para realizar cálculos matemáticos básicos y avanzados.
                    """
                  
                

Buenas Prácticas para Paquetes

  • Organización y estructura:
    • Diseñar paquetes con una jerarquía lógica y responsabilidades claras.
    • Mantener los módulos pequeños y evitar dependencias circulares.
    • Crear una estructura ordenada que facilite la navegación.
  • Nombrado:
    • Usar nombres significativos, cortos y en minúsculas para módulos y paquetes.
    • Evitar nombres que puedan chocar con módulos estándar de Python.
  • Uso del archivo __init__.py:
    • Documentar el propósito del paquete en un docstring.
    • Simplificar importaciones exportando funciones clave en __init__.py.
    • Controlar lo que se expone con la variable __all__.
  • Importaciones:
    • Usar rutas relativas dentro del paquete para mejorar la portabilidad.
    • Evitar from paquete import * para mantener claridad y evitar conflictos de nombres.
  • Documentación:
    • Documentar cada módulo, función y clase con docstrings claros.
    • Incluir un archivo README.md. que explique el propósito del paquete y cómo usarlo.
  • Pruebas:
    • Agregar pruebas unitarias para cada módulo y usar herramientas como pytest.
    • Mantener las pruebas en un directorio separado dentro del proyecto.
  • Distribución:
    • Preparar un archivo setup.py para definir cómo se instala el paquete.
    • Documentar las dependencias y asegurarse de que el paquete cumpla estándares si se publicará en PyPI.
  • Estilo y calidad:
    • Seguir las normas de PEP 8 para escribir código limpio y legible.
    • Usar herramientas como flake8 o black para mantener la calidad del código.
    • Comentar adecuadamente partes complejas del código.

Primer Módulo

Módulo

Un módulo es simplemente un archivo con extensión .py que contiene código Python, como funciones, variables o clases. Los módulos ayudan a dividir el código en partes reutilizables y organizadas.

Manejo de Módulos

  • module.py: Archivo que contiene el código del módulo.
                          
                            print("Me gusta ser un módulo.")
                          
                        
  • main.py: En este archivo se importa el módulo module.py, ambos archivos deben estar en la misma carpeta.
                          
                            import module
                          
                        
  • Ejecutar main.py: se debe ver el mensaje "Me gusta ser un módulo".
  • Carpeta __pycache__: Al ejecutar el archivo main.py se crea una carpeta con el nombre __pycache__, el cual contiene el archivo module.cpython-xy.pyc:
  • Archivo module.cpython-xy.pyc:
    • El archivo se puede llamar (más o menos) module.cpython-xy.pyc donde x y y son dígitos derivados de la versión de Python (por ejemplo, serán 3 y 8 si s utiliza Python 3.8).
    • El nombre del archivo es el mismo que el del módulo. La parte posterior al primer punto dice qué implementación de Python ha creado el archivo (CPython) y su número de versión. La ultima parte (pyc) viene de las palabras Python y compilado.
    • Cuando Python importa un módulo por primera vez, traduce el contenido a una forma algo compilada.
    • El archivo no contiene código en lenguaje máquina: es código semi-compilado interno de Python, listo para ser ejecutado por el intérprete de Python. Como tal archivo no requiere tantas comprobaciones como las de un archivo fuente, la ejecución comienza más rápido y también se ejecuta más rápido.
    • Gracias a eso, cada vez que se importe este archivo posteriormente será más rápida que interpretar el código fuente desde cero.
    • Python puede verificar si el archivo fuente del módulo ha sido modificado (en este caso, el archivo pyc será reconstruido) o no (cuando el archivo pyc pueda ser ejecutado al instante). Este proceso es completamente automático y transparente, no tiene que ser tomando en cuenta.
  • Ejecutar module.py: se debe ver el mensaje "Me gusta ser un módulo" otra vez.
  • Como se puede ver no hay ninguna diferencia en el resultado de la ejecución del código directamente desde el módulo module.py o desde un script main.py, para poder diferenciar quien ejecutó el código se usa la variable __name__.
  • variable __name__: En Python, la variable especial __name__ es una cadena que se utiliza para determinar si un archivo Python está siendo ejecutado directamente o importado como un módulo. Esto es especialmente útil para controlar qué partes del código se ejecutan dependiendo del contexto.

Contextos de Uso de __name__

  • Cuando un archivo se ejecuta directamente: Si se ejecuta directamente, Python asigna a __name__ el valor __main__. Esto permite identificar que el archivo es el programa principal.
  • Cuando un archivo se importa como módulo: Si el archivo es importado en otro archivo, Python asigna a __name__ el nombre del archivo sin la extensión .py. Esto asegura que el bloque protegido con if __name__ == __main__: no se ejecute.
    Si al archivo module.py se le adiciona la instrucción print(__name__) como se muestra a continuación:
                            
                              # module.py
                              print("Me gusta ser un módulo.")
                              print(__name__)
                              # Salida: __main__
                            
                          

    Al ejecutar este módulo la variable __name__ toma el valor de __main__.

    Si ejecuta el script que trabaja como paquete, main.py, la variable __name__ toma el valor de module es decir el nombre del archivo o módulo que se está importando sin la extensión .py.

                          
                            # main.py
                            import module
                            # Salida: module
                          
                        

    Sucede lo mismo con todos los módulos importados en el archivo main.py.

Buenas Prácticas para Módulos

  • Usar nombres descriptivos y en minúsculas:
    • El nombre del módulo debe reflejar claramente su propósito.
    • Evitar nombres genéricos como utilidades.py o funciones.py.
    • Ejemplo: calculos_financieros.py es más descriptivo que calculos.py.
  • Evitar el uso de nombres de módulos conflictivos:No nombrar módulos con nombres que coincidan con bibliotecas estándar de Python (por ejemplo, math.py o json.py).
  • Agrupar funciones relacionadas: Un módulo debe contener funciones, clases o variables que tengan un propósito común. Esto mejora la coherencia y facilita el mantenimiento.
  • Evitar demasiadas responsabilidades en un módulo: Si un módulo crece demasiado, divídalo en varios módulos más pequeños.
  • Documentar el módulo con un docstring: Incluir un resumen breve al principio del archivo que describa su propósito y cómo se usa.
  • Controlar lo que se exporta: Utilizar la variable __all__ para definir qué funciones, variables o clases estarán disponibles al usar from modulo import *.
                            
                              # Exportar únicamente lo necesario
                              __all__ = ['suma', 'promedio']
                            
                          

Plantilla Ejemplo

Se muestra un código nuevo del archivo module.py. El módulo actualizado está aquí:

                    
                      #!/usr/bin/env python3 
                      "" module.py - an example of a Python module ""
                      __counter = 0
                      def suml(the_list):
                        global __counter
                        __counter += 1
                        the_sum = 0
                        for element in the_list:
                            the_sum += element
                        return the_sum
                        def prodl(the_list):
                            global __counter
                            __counter += 1
                            prod = 1
                            for element in the_list:
                            prod *= element
                            return prod
                      if __name__ == "__main__":
                        print("Prefiero ser un módulo, pero puedo hacer algunas pruebas para usted.")
                        my_list = [i+1 for i in range(5)]
                        print(suml(my_list) == 15)
                        print(prodl(my_list) == 120)
                    
                  

La línea que comienza con #! recibe múltiples nombres, como shabang, shebang, hashbang, poundbang o incluso hashpling. Desde la perspectiva de Python, esta línea no es más que un comentario, ya que comienza con el carácter #. Sin embargo, para los sistemas operativos basados en Unix y similares (incluido macOS), esta línea instruye al sistema operativo sobre cómo ejecutar el contenido del archivo, especificando qué programa debe interpretar el texto. En ciertos entornos, especialmente en aquellos relacionados con servidores web, la ausencia de esta línea puede ocasionar problemas de funcionamiento.

Por otro lado, una cadena de texto (que puede ser multilínea) ubicada antes de cualquier instrucción dentro de un módulo, incluidas las declaraciones de importación, se denomina doc-string. Su propósito es proporcionar una breve descripción del objetivo y contenido del módulo.

Las funciones definidas en el módulo, como suml() y prodl(), están disponibles para ser importadas y utilizadas en otros archivos.

Python no ofrece mecanismos para restringir el acceso a variables privadas de manera que solo puedan ser utilizadas dentro del módulo al que pertenecen. Se puede comunicar a los usuarios que esta variable es de uso exclusivo para lectura y que no debe ser modificada bajo ninguna circunstancia. Para indicar esta restricción, se antepone un guion bajo _ o dos guiones bajos __ al nombre de la variable. Sin embargo, es importante destacar que esta práctica es únicamente un acuerdo implícito y no una regla obligatoria, por lo que los usuarios del módulo pueden decidir si respetan esta convención o no.

Adicionalmente, la variable especial __name__ se utiliza para identificar si el archivo se está ejecutando de forma independiente. En tal caso, se aprovecha esta característica para realizar pruebas simples del código.

Primer Paquete

¿Qué Es un Paquete en Python?

Un paquete es una carpeta que:

  • Contiene un archivo especial llamado __init__.py (en versiones modernas de Python, este archivo puede ser opcional).
  • Agrupa varios módulos relacionados.
  • Puede contener subpaquetes, organizando el código en niveles jerárquicos.
                  
                    mi_paquete/
                        __init__.py
                        modulo1.py
                        modulo2.py
                        subpaquete/
                            __init__.py
                            modulo3.py
                  
                

En esta estructura:

  • mi_paquete es el paquete principal.
  • subpaquete es un subpaquete dentro de mi_paquete.
  • modulo1.py, modulo2.py, y modulo3.py son módulos que contienen funciones, clases o variables.

Crear un Paquete

  • Crear un directorio: Este será el nombre del paquete.
  • Añadir un archivo mi_paquete/__init__.py: Este archivo puede estar vacío o contener código para inicializar el paquete (por ejemplo, importar módulos por defecto).
    Ejemplo: mi_paquete/__init__.py puede contener:
                          
                            from .modulo1 import funcion1
                            from .modulo2 import clase2
                          
                        
  • Añadir módulos al paquete: Crea archivos .py dentro de la carpeta del paquete.
    Ejemplo de modulo1.py:
                          
                            def funcion1():
                                print("Hola desde modulo1!")
                          
                        

Importar y Usar un Paquete

Una vez que el paquete está configurado, puede ser usado como un módulo normal en Python.

Ejemplo:

  • Crear la siguiente estructura:
                          
                            mi_paquete/
                                __init__.py
                                modulo1.py
                                modulo2.py
                          
                        
  • Código en modulo1.py:
                          
                            def funcion1():
                                return "Función en modulo1"
                          
                        
  • Código en modulo2.py:
                          
                            def funcion2():
                                return "Función en modulo2"
                          
                        
  • Importar en un script Python:
                          
                            from mi_paquete import modulo1, modulo2
                            print(modulo1.funcion1())  # Salida: Función en modulo1
                            print(modulo2.funcion2())  # Salida: Función en modulo2
                          
                        

Paquetes con Subpaquetes

Si se tienen subpaquetes, se pueden organizar importaciones jerárquicas.

Ejemplo de estructura:

                  
                    mi_paquete/
                        __init__.py
                        modulo1.py
                        subpaquete/
                            __init__.py
                            modulo3.py
                  
                

Para usar el subpaquete:

                  
                    from mi_paquete.subpaquete import modulo3
                    # Llamar funciones o clases de modulo3
                    resultado = modulo3.funcion3()
                    print(resultado)
                  
                

Instalar y Usar Paquetes Externos

Python usa pip para instalar paquetes externos desde el índice PyPI.

  • Instalar un paquete:
                          
                            pip install numpy
                          
                        
  • Usar el paquete instalado:
                          
                            import numpy as np
                            array = np.array([1, 2, 3])
                            print(array)
                          
                        

Buenas Prácticas

  • Usa nombres descriptivos para paquetes y módulos.
  • Evita conflictos de nombres (no uses nombres como os.py o sys.py).
  • Estructura el proyecto en paquetes para mantener el código organizado.
  • Documenta los __init__.py para que otros sepan qué módulos contiene el paquete.

Diferencias entre Módulos y Paquetes

Aspecto Módulo Paquete
Definición Un módulo es un archivo .pyque contiene código Python reutilizable, como funciones, clases y variables. Un paquete es un directorio que contiene módulos y subpaquetes, junto con un archivo especial __init__.py.
Propósito Permite dividir el código en partes pequeñas y reutilizables para mantener la organización. Agrupa y organiza varios módulos relacionados en un nivel jerárquico, ideal para proyectos grandes.
Estructura Es un solo archivo Python. Es una carpeta con módulos y un archivo __init__.py.
Ejemplo Archivo calculos.py con funciones matemáticas. Carpeta matematicas/ que contiene módulos como calculos.py, estadisticas.py, y __init__.py.
Importación Se importa directamente usando import modulo. Se importa como un conjunto jerárquico, por ejemplo, from paquete.modulo import función.
Nivel de complejidad Más simple, ideal para proyectos pequeños o funcionalidades específicas. Más complejo, diseñado para proyectos más grandes o estructuras modulares avanzadas.

Cuándo Usar Módulos y Paquetes

  • Módulos: Úselos para scripts o funcionalidades independientes, cuando el proyecto es pequeño y no requiere organización compleja.
  • Paquetes: Son útiles para proyectos grandes que requieren organización jerárquica y agrupación de funcionalidades relacionadas.

COMENTARIOS

Si tiene alguna inquietud, duda o ha encontrado algún error, por favor infórmelo a través del formulario disponible para este propósito.

La política de privacidad, y los términos y condiciones están disponibles en el formulario de contacto.