Saltar al contenido
modulos.py · devschool

Módulos e importaciones en Python

Lección 14 de 19 · 9 min de lectura · Actualizado el

En esta lección
  1. Qué es un módulo
  2. Formas de importar
  3. Crear tu propio módulo
  4. if __name__ == "__main__"
  5. Paquetes
  6. La biblioteca estándar
  7. Dónde busca Python los módulos: sys.path
  8. Buenas prácticas con los imports
  9. Errores frecuentes
  10. Resumen

Cuando un programa crece, meterlo todo en un único archivo se vuelve inmanejable. Python te permite repartir el código en módulos (archivos .py) y paquetes (carpetas de módulos), e importar en cada sitio solo lo que necesitas. Además, Python trae de serie una enorme biblioteca estándar con módulos para matemáticas, fechas, ficheros, JSON y mucho más. En esta lección aprenderás a importar, a crear tus propios módulos y a sacar partido de los módulos más útiles.

Qué es un módulo

Un módulo es simplemente un archivo .py. Su nombre es el del archivo sin la extensión: calculos.py es el módulo calculos. Todo lo que definas en él (variables, funciones, clases) se puede usar desde otros archivos.

¿Por qué dividir el código?

  • Organización: cada archivo se ocupa de una cosa (cálculos, acceso a datos, interfaz).
  • Reutilización: escribes una función una vez y la importas donde haga falta.
  • Espacios de nombres: calculos.total y pedidos.total pueden convivir sin chocar.

Formas de importar

import modulo

Importa el módulo entero. Para usar lo que contiene, escribes el nombre del módulo, un punto y el elemento:

import math

print(math.sqrt(16))   # 4.0
print(math.pi)         # 3.141592653589793

Es la forma más clara: al leer math.sqrt sabes exactamente de dónde viene sqrt.

from modulo import nombre

Trae solo algunos elementos, que luego usas sin prefijo:

from math import sqrt, pi

print(sqrt(81))   # 9.0
print(pi)         # 3.141592653589793

Es cómodo si usas mucho una función concreta, pero pierdes la pista de su origen en archivos largos.

as: poner un alias

as da otro nombre a un módulo o a un elemento. Se usa para acortar nombres largos o evitar choques:

import statistics as st
from math import sqrt as raiz

print(st.mean([6, 8, 10]))   # 8
print(raiz(25))              # 5.0

Algunos alias son convenciones universales que verás en todas partes, como import numpy as np o import pandas as pd.

from modulo import * (evítalo)

Importa todos los nombres públicos del módulo de golpe. Parece práctico, pero no sabes qué nombres has traído y alguno puede sobrescribir una variable tuya sin que te des cuenta. En código serio no se usa.

Crear tu propio módulo

Crea un archivo calculos.py:

"""Funciones de cálculo para la tienda."""

IVA = 0.21

def precio_con_iva(precio):
    return round(precio * (1 + IVA), 2)

def aplicar_descuento(precio, porcentaje):
    return round(precio * (1 - porcentaje / 100), 2)

Y en la misma carpeta, un archivo main.py que lo use:

import calculos
from calculos import aplicar_descuento

print(calculos.precio_con_iva(20))   # 24.2
print(calculos.IVA)                  # 0.21
print(aplicar_descuento(80, 25))     # 60.0

Ejecutas python main.py y listo. Python busca calculos.py en la carpeta del programa que estás ejecutando.

Cuidado: no llames a tus archivos igual que un módulo de Python (random.py, math.py, json.py…). Tu archivo “taparía” al original y import random cargaría el tuyo, con errores muy desconcertantes como AttributeError: module 'random' has no attribute 'randint'.

Cuando importas un módulo, Python ejecuta todo su código una vez. Las importaciones posteriores del mismo módulo reutilizan el que ya está cargado.

if __name__ == "__main__"

Como importar ejecuta el archivo, si calculos.py tuviera print de prueba sueltos, aparecerían al importarlo desde main.py. Para evitarlo existe este patrón:

# al final de calculos.py
if __name__ == "__main__":
    print("Probando calculos.py...")
    print(precio_con_iva(100))       # 121.0
    print(aplicar_descuento(50, 10)) # 45.0

Cada módulo tiene una variable especial __name__:

Cómo se usa el archivoValor de __name__
Lo ejecutas directamente: python calculos.py"__main__"
Otro archivo lo importa: import calculos"calculos"

Así, el bloque del if solo se ejecuta cuando lanzas el archivo directamente. Es ideal para pruebas rápidas o para que un archivo sirva a la vez como módulo y como programa. Muchos programas terminan con:

def main():
    ...

if __name__ == "__main__":
    main()

Paquetes

Un paquete es una carpeta que agrupa módulos relacionados. Se marca con un archivo __init__.py (que puede estar vacío):

mi_proyecto/
├── app.py
└── tienda/
    ├── __init__.py
    ├── productos.py
    └── pedidos.py
# tienda/productos.py
def crear_producto(nombre, precio):
    return {"nombre": nombre, "precio": precio}

Desde app.py se importa usando puntos para indicar la ruta:

from tienda.productos import crear_producto
from tienda import pedidos
import tienda.productos

print(crear_producto("libro", 12))   # {'nombre': 'libro', 'precio': 12}

Dentro del propio paquete, un módulo puede importar a otro con un import relativo, usando un punto para “este paquete”:

# tienda/pedidos.py
from .productos import crear_producto

__init__.py se ejecuta al importar el paquete. Puedes dejarlo vacío o usarlo para exponer lo más importante: si pones from .productos import crear_producto, podrás escribir directamente from tienda import crear_producto.

Consejo: desde Python 3.3 una carpeta sin __init__.py también se puede importar (se llama namespace package), pero para tus proyectos incluye siempre __init__.py: deja claro que es un paquete y evita sorpresas.

La biblioteca estándar

Python viene “con las pilas incluidas”: cientos de módulos listos para usar sin instalar nada. Estos son los que más usarás.

math: matemáticas

import math

print(math.sqrt(16), math.ceil(4.1), math.floor(4.9))   # 4.0 5 4
print(math.hypot(3, 4))   # 5.0 (hipotenusa)

random: números aleatorios

import random

dado = random.randint(1, 6)                             # entero entre 1 y 6, ambos incluidos
jugada = random.choice(["piedra", "papel", "tijera"])   # un elemento al azar
cartas = [1, 2, 3, 4, 5]
random.shuffle(cartas)                                  # desordena la lista
primitiva = random.sample(range(1, 50), 6)              # 6 números sin repetir

La salida cambia en cada ejecución, que es justo lo que se busca.

os: el sistema operativo

import os

print(os.getcwd())                                   # carpeta de trabajo actual
print(os.path.join("datos", "ventas.csv"))           # datos/ventas.csv (datos\ventas.csv en Windows)
print(os.environ.get("API_KEY", "sin clave"))        # variable de entorno

sys: el intérprete

import sys

print(sys.version)   # versión de Python
print(sys.argv)      # argumentos de la línea de comandos

Si ejecutas python std.py a b, sys.argv vale ['std.py', 'a', 'b'].

pathlib: rutas modernas

from pathlib import Path

ruta = Path("datos") / "ventas.csv"
print(ruta.name, ruta.suffix, ruta.stem)   # ventas.csv .csv ventas

Lo verás a fondo en ficheros. Hoy se prefiere a os.path.

datetime: fechas

from datetime import date

print(date(2025, 12, 25) - date(2025, 12, 1))   # 24 days, 0:00:00

Tiene su propia lección: fechas con datetime.

json y csv: formatos de datos

import json

texto = json.dumps({"nombre": "Ana", "notas": [8, 9]})
print(texto)                                        # {"nombre": "Ana", "notas": [8, 9]}
print(json.loads('{"activo": true, "edad": null}')) # {'activo': True, 'edad': None}
import csv

with open("productos.csv", encoding="utf-8") as f:
    for fila in csv.DictReader(f):
        print(fila)   # {'nombre': 'pan', 'precio': '1.2'} ...

Los dos se explican en detalle en ficheros y JSON.

collections: estructuras extra

from collections import Counter, defaultdict

votos = ["rojo", "azul", "rojo", "verde", "rojo", "azul"]
conteo = Counter(votos)
print(conteo)                  # Counter({'rojo': 3, 'azul': 2, 'verde': 1})
print(conteo.most_common(1))   # [('rojo', 3)]

por_ciudad = defaultdict(list)
for nombre, ciudad in [("Ana", "Madrid"), ("Luis", "Sevilla"), ("Eva", "Madrid")]:
    por_ciudad[ciudad].append(nombre)   # no hace falta comprobar si la clave existe
print(dict(por_ciudad))        # {'Madrid': ['Ana', 'Eva'], 'Sevilla': ['Luis']}

itertools: combinar iterables

import itertools

print(list(itertools.combinations(["Ana", "Luis", "Eva"], 2)))
# [('Ana', 'Luis'), ('Ana', 'Eva'), ('Luis', 'Eva')]   (parejas posibles)

print(list(itertools.chain([1, 2], [3], [4, 5])))   # [1, 2, 3, 4, 5]

statistics: estadística básica

import statistics

notas = [6, 7.5, 8, 5, 9, 7.5]
print(statistics.mean(notas))     # 7.166666666666667 (media)
print(statistics.median(notas))   # 7.5 (mediana)
print(statistics.mode(notas))     # 7.5 (moda)

Para explorar un módulo desde la consola interactiva, usa dir(math) para ver su contenido y help(math.sqrt) para leer la documentación de una función.

Dónde busca Python los módulos: sys.path

Al hacer import algo, Python busca en una lista de carpetas guardada en sys.path, en este orden:

  1. La carpeta del script que estás ejecutando.
  2. Las carpetas de la variable de entorno PYTHONPATH, si existe.
  3. La biblioteca estándar.
  4. La carpeta site-packages, donde se instalan los paquetes externos con pip.
import sys

for carpeta in sys.path:
    print(carpeta)

Si obtienes ModuleNotFoundError: No module named 'calculos', casi siempre es porque ejecutas el programa desde otra carpeta o el archivo no está donde crees. Si el módulo es externo (como requests), significa que no está instalado en el entorno que usas.

Cuidado: aunque se puede, no modifiques sys.path a mano para “arreglar” un import. Organiza bien tu proyecto en paquetes y ejecútalo desde su carpeta raíz.

Buenas prácticas con los imports

  • Pon todos los imports al principio del archivo, después del docstring del módulo.
  • Agrúpalos en tres bloques separados por una línea en blanco: biblioteca estándar, paquetes externos y tus módulos.
  • Un import por línea cuando son módulos distintos: import os e import sys en líneas separadas.
  • Prefiere import modulo o from modulo import nombre concretos. Nunca import *.
  • Nombres de módulos cortos, en minúsculas y con guion bajo si hace falta: gestion_pedidos.py.
"""Programa principal de la tienda."""

import json
import sys
from pathlib import Path

import requests

from tienda.productos import crear_producto

Errores frecuentes

  • Llamar a tu archivo como un módulo estándar (random.py, csv.py): tapa al original.
  • ModuleNotFoundError: el archivo no está en sys.path o el paquete no está instalado en el entorno activo.
  • Olvidar el prefijo: tras import math, escribir sqrt(4) da NameError; hay que poner math.sqrt(4).
  • Código de prueba sin if __name__ == "__main__": se ejecuta cada vez que alguien importa el módulo.
  • Imports circulares: si a.py importa b.py y b.py importa a.py, puedes obtener errores raros. Suele indicar que hay que reorganizar el código.

Resumen

SintaxisQué hace
import moduloImporta el módulo; se usa como modulo.nombre
from modulo import a, bTrae nombres concretos para usarlos sin prefijo
import modulo as mImporta con un alias
from .modulo import xImport relativo dentro de un paquete
if __name__ == "__main__":Código que solo se ejecuta al lanzar el archivo directamente
__init__.pyMarca una carpeta como paquete
sys.pathLista de carpetas donde Python busca los módulos

Con la biblioteca estándar resuelves muchísimas tareas sin instalar nada. Cuando necesites más, instalarás paquetes externos con pip y entornos virtuales.

Pon a prueba lo que has aprendido

[Python] Tienes saludos.py con este código y ejecutas python main.py, cuyo contenido es import saludos. ¿Qué se muestra?
# saludos.py
print("cargando", __name__)

if __name__ == "__main__":
    print("prueba")

[Python] Después de import math, ¿qué línea funciona?

[Python] Creas un archivo llamado random.py con tu juego y dentro escribes import random y random.randint(1, 6). ¿Qué pasa?

[Python] ¿Qué imprime este código?
from collections import Counter
print(Counter("banana").most_common(1))

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.