Saltar a contenido

Módulos, Paquetes e Imports en Python

Módulos en python

Un módulo es un archivo .py con código Python.

Ejemplo:

# archivo: libro.py
class Libro:
    def __init__(self, titulo):
        self.titulo = titulo

Podemos importar su contenido desde otro archivo que esté en la misma carpeta:

# archivo: ejemplo.py
from libro import Libro

libro = Libro("1984")
print(libro.titulo)

Cuando haces import, Python busca el archivo .py con ese nombre.

Paquetes

Un paquete es una carpeta que contiene módulos y un archivo especial llamado __init__.py.

biblioteca/
├── __init__.py
├── libro.py
└── repositorio_libros.py

Esto permite importar con una ruta jerárquica:

from biblioteca.libro import Libro

El archivo __init__.py indica que la carpeta es un paquete importable.

Paquetes y subpaquetes

Si tenemos esta estructura:

biblioteca/
├── __init__.py
├── domain/
│   ├── __init__.py
│   ├── libro.py
│   └── repositorio_libros.py

hace que Python reconozca:

  • biblioteca como un paquete,
  • biblioteca.domain como un subpaquete,
  • biblioteca.domain.libro como un módulo.

__init.py__

Como hemos visto, en Python, una carpeta solo se considera un paquete importable si contiene un archivo llamado __init__.py.

Si no hay un __init__.py, Python no sabrá que esa carpeta forma parte del paquete, y los imports como from biblioteca.domain.libro import Libro fallarán (a menos que uses namespace packages, que es un tema más avanzado).

El archivo __init__.py:

  • Puede estar vacío.
  • O puede ejecutar código al importar el paquete.
  • También puede usarse para exponer elementos del paquete.

Ejemplo:

# biblioteca/domain/__init__.py
from .libro import Libro

Entonces la clase Libro se puede importar así:

from biblioteca.domain import Libro
Ya que cuando Python ve la línea anterior busca el paquete biblioteca.domain, carga su __init__.py y revisa qué nombres están definidos allí.

Como dentro del __init__.py se importó Libro, entonces Libro ya está disponible como parte del paquete.

Esto se hace para simplificar los imports y definir qué símbolos “públicos” ofrece el paquete.

El sys.path

sys.path es una lista de rutas donde Python busca módulos. Puede consultarse con:

import sys
print(sys.path)

Cuando ejecutas:

python -m biblioteca.presentation.menu

Python añade la carpeta que contiene biblioteca/ a sys.path, por eso los imports absolutos funcionan.

Funcionamiento de import

Cuando escribes:

from biblioteca.libro import Libro

Python hace lo siguiente:

  1. Busca en sys.path (una lista de rutas donde busca módulos).
  2. Encuentra la carpeta que contiene biblioteca/.
  3. Entra en biblioteca/ y busca el archivo libro.py.
  4. Ejecuta el código de libro.py (si no se ha ejecutado antes) y carga la clase Libro en memoria.

Tipos de imports

a) Import absoluto (recomendado)

Importa desde la raíz del paquete.

from biblioteca.domain.libro import Libro

Es la forma más clara y segura.

b) Import relativo

Usa puntos para moverse entre carpetas dentro del mismo paquete.

from ..domain.libro import Libro
  • . → mismo nivel
  • .. → subir un nivel
  • ... → subir dos niveles

Solo funciona si se ejecuta el proyecto como módulo con -m, por ejemplo:

python -m biblioteca.presentation.menu

c) Error común: ejecutar desde dentro de la carpeta

Si ejecutas:

cd biblioteca
python presentation/menu.py

y dentro tienes:

from biblioteca.application.servicios import ServicioBiblioteca

obtendrás:

ModuleNotFoundError: No module named 'biblioteca'

Porque al ejecutar desde dentro de biblioteca/, Python ya no la ve como paquete raíz.

Ejemplo de imports

Si el proyecto tiene la siguiente estructura de carpetas

biblioteca/
├── __init__.py
├── domain/
│   ├── __init__.py
│   ├── libro.py
│   └── repositorio_libros.py
├── application/
│   ├── __init__.py
│   └── servicios.py
├── infrastructure/
│   ├── __init__.py
│   └── repositorio_memoria.py
└── presentation/
    ├── __init__.py
    └── menu.py

Imports correctos entre capas

De forma esquemática:

(raíz del proyecto)
└── biblioteca/
    ├── presentation/
    │   └── menu.py         → importa application
    ├── application/
    │   └── servicios.py    → importa domain
    ├── domain/
    │   └── libro.py
    └── infrastructure/
        └── repositorio_memoria.py → importa domain

Flujo de dependencias:

presentation → application → domain
             infrastructure
Archivo Importaciones correctas
application/servicios.py from biblioteca.domain.libro import Libro
from biblioteca.domain.repositorio_libros import RepositorioLibros
infrastructure/repositorio_memoria.py from biblioteca.domain.repositorio_libros import RepositorioLibros
from biblioteca.domain.libro import Libro
presentation/menu.py from biblioteca.application.servicios import ServicioBiblioteca
from biblioteca.infrastructure.repositorio_memoria import RepositorioLibrosMemoria

Reglas generales:

  • las capas superiores importan a las inferiores, nunca al revés.
  • El dominio no debe importar la aplicación ni la infraestructura.

Cómo ejecutar el proyecto

Estando un nivel por encima de la carpeta biblioteca/, ejecuta:

python -m biblioteca.presentation.menu

Esto le dice a Python que ejecute el archivo menu.py dentro del paquete biblioteca.presentation.

Así Python sabe que biblioteca es el paquete raíz y puede resolver imports como:

from biblioteca.domain.libro import Libro

Conclusión

Las ideas más importantes que se recogen en estos apuntes son:

Concepto Explicación Ejemplo
Módulo Archivo .py libro.py
Paquete Carpeta con __init__.py biblioteca/domain/
Import absoluto Desde la raíz del paquete from biblioteca.domain.libro import Libro
Import relativo Con . o .. dentro del paquete from ..domain.libro import Libro
Ejecutar módulo Forma correcta de ejecutar python -m biblioteca.presentation.menu
Regla de dependencias Las capas superiores usan las inferiores presentation → application → domain