Guía de estudio interactiva · de cero a avanzado

Aprende Python desde cero

Una guía para aprender a programar en Python, aunque nunca hayas escrito una línea de código. Cada lección explica una idea con palabras simples y trae ejemplos que puedes ejecutar y modificar aquí mismo, un ejercicio para practicar y una pregunta para comprobar que lo entendiste.

for i in range(1, 4):
    print(f"Lección {i}: ¡hecha!")
Lección 1: ¡hecha!
Lección 2: ¡hecha!
Lección 3: ¡hecha!
▶ Ejecutar corre el código en tu navegador Editar cámbialo y vuelve a ejecutarlo Ver resultado muestra la salida esperada Tu turno practica sin mirar la solución
BásicoLección 0

Antes de empezar

Objetivo: entender qué es programar, ejecutar tu primer código y aprender a leer un error.

Programar es escribir instrucciones para que la computadora las siga, una por una y en orden. Python es uno de los lenguajes más usados para eso porque se lee casi como inglés. Con él se hacen páginas web, se automatizan tareas aburridas, se analizan datos y se crea inteligencia artificial.

AnalogíaUn programa es como una receta de cocina. La computadora es un cocinero muy rápido, pero completamente literal: hace exactamente lo que dice la receta, ni más ni menos. Si la receta tiene un error de escritura, se detiene y te avisa.

Dónde escribir Python

OpciónPara quién
Esta misma páginaPara empezar ya. Pulsa ▶ Ejecutar en cualquier ejemplo. La primera vez tarda unos segundos en cargar.
Google ColabGratis, en el navegador, con cuenta de Google. Ideal para practicar y guardar tus cuadernos.
python.org + VS CodePara programar en tu computadora. Al instalar Python en Windows, marca la casilla “Add python.exe to PATH”.

Tu primer programa

print("¡Hola, mundo!")

print() es una función: una orden con nombre que hace algo. Lo que pones entre los paréntesis es lo que se muestra. El texto va entre comillas.

print("Estoy aprendiendo Python")
print(2026)
print("Mi edad es", 20)   # print acepta varias cosas separadas por coma

Todo lo que va después de # es un comentario: Python lo ignora. Úsalos para explicar tu código.

Leer un error (sin miedo)

Los errores son normales: los programadores con experiencia los ven todo el día. Lo importante es leerlos. Ejecuta esto:

nombre = "Ana"
print(nombe)

Léelo de abajo hacia arriba. La última línea dice qué pasó (NameError: ese nombre no existe) e incluso sugiere la solución: quizás quisiste escribir nombre. Las líneas de arriba dicen dónde: línea 2. Corrígelo con Editar y ejecútalo de nuevo.

Comprueba

Aparece un error largo en pantalla. ¿Por dónde empiezas a leerlo?

BásicoLección 1

Variables y tipos de datos

Objetivo: guardar información con un nombre y conocer los cuatro tipos de datos básicos.

Una variable es un nombre que guarda un valor. Se crea con =, que en Python no significa “es igual a”, sino “guarda esto aquí”.

nombre = "Ana"        # texto (str)
edad = 20             # número entero (int)
altura = 1.65         # número decimal (float)
estudiante = True     # verdadero/falso (bool)

print(nombre, edad, altura, estudiante)
AnalogíaUna variable es una caja con etiqueta. edad = 20 es “mete el 20 en una caja llamada edad”. Después escribes edad y Python saca lo que hay dentro.
TipoQué guardaEjemplo
strTexto, entre comillas"Ana", 'hola'
intNúmeros enteros20, -3
floatNúmeros con decimales (con punto)1.65
boolVerdadero o falsoTrue, False

Con type() preguntas de qué tipo es algo:

print(type(nombre))
print(type(edad))
print(type(altura))
print(type(estudiante))

Convertir entre tipos

print(int("25") + 5)       # texto -> entero
print(float("3.5") * 2)    # texto -> decimal
print(str(100) + " puntos")  # número -> texto
print(int(7.9))            # int() corta los decimales, no redondea
print(round(7.9))          # round() sí redondea

Las variables cambian

x = 5
print(x)
x = x + 1      # toma el valor actual, le suma 1 y lo guarda de nuevo
print(x)
x = "cinco"    # una variable puede cambiar de tipo
print(x)

Reglas para los nombres: letras, números y _, sin espacios, sin empezar con número. Python distingue mayúsculas: Edad y edad son distintas. La costumbre es usar minúsculas con guion bajo: precio_total.

Tu turno Crea variables para un producto (nombre, precio y cantidad), calcula el total y muéstralo.
Ver solución
producto = "Cuaderno"
precio = 3.5
cantidad = 4
total = precio * cantidad
print("Producto:", producto)
print("Total a pagar:", total)
Comprueba

¿De qué tipo es "42"?

BásicoLección 2

Operadores

Objetivo: hacer cuentas, comparar valores y combinar condiciones.

Aritméticos

print(7 + 2)    # suma
print(7 - 2)    # resta
print(7 * 2)    # multiplicación
print(7 / 2)    # división (siempre da decimal)
print(7 // 2)   # división entera
print(7 % 2)    # resto (módulo)
print(7 ** 2)   # potencia

// y % son más útiles de lo que parecen: % te dice si un número es par (n % 2 == 0) y, junto con //, sirve para convertir minutos en horas.

print(2 + 3 * 4)      # primero la multiplicación
print((2 + 3) * 4)    # los paréntesis mandan
TrampaLa potencia es **, no ^. Y el decimal se escribe con punto: 3.5. Con coma, 3,5 son dos números distintos.

De comparación: dan True o False

print(5 > 3)
print(5 == 5.0)      # == compara; = asigna
print(3 != 3)
print("a" < "b")     # los textos se comparan en orden alfabético

Lógicos: and, or, not

edad = 20
tiene_entrada = False

print(edad >= 18 and tiene_entrada)   # and: las dos deben ser verdad
print(edad >= 18 or tiene_entrada)    # or: basta con una
print(not tiene_entrada)              # not: invierte

Asignación abreviada

puntos = 10
puntos += 5     # igual que: puntos = puntos + 5
puntos *= 2     # igual que: puntos = puntos * 2
puntos -= 3
print(puntos)
Tu turno ¿El número 17 es par? Convierte 135 minutos en horas y minutos.
Ver una pista

Un número es par si el resto de dividirlo entre 2 es 0. Para las horas usa // y para los minutos sobrantes, %.

Ver solución
numero = 17
print(numero % 2 == 0)     # ¿es par?
minutos = 135
print(minutos // 60, "horas y", minutos % 60, "minutos")
Comprueba

¿Cuánto da 2 + 3 * 4?

BásicoLección 3

Texto (strings)

Objetivo: recortar, transformar y armar textos.

Posiciones: se cuenta desde 0

palabra = "Python"
print(palabra[0])      # primera letra (se cuenta desde 0)
print(palabra[-1])     # última letra
print(palabra[0:3])    # de la 0 a la 2 (el 3 no se incluye)
print(palabra[::-1])   # al revés
print(len(palabra))    # longitud
Lo más confuso al principioPython cuenta las posiciones desde 0: la primera letra es [0]. En un rango [0:3] se incluye el inicio pero no el final. Los números negativos cuentan desde el final.

Métodos: acciones que el texto sabe hacer

Un método se escribe con un punto después del valor: texto.upper().

frase = "  Aprender Python es divertido  "
print(frase.strip())                  # quita espacios de los extremos
print(frase.upper())                  # mayúsculas
print(frase.lower())                  # minúsculas
print(frase.replace("divertido", "útil"))
print(frase.split())                  # separa en una lista de palabras
print(frase.count("e"))               # cuántas veces aparece "e"

f-strings: meter variables en un texto

Pon una f antes de las comillas y escribe las variables entre llaves { }.

nombre = "Ana"
edad = 20
print(f"Me llamo {nombre} y tengo {edad} años")
print(f"El próximo año tendré {edad + 1}")

precio = 1234.5678
print(f"{precio:.2f}")      # 2 decimales
print(f"{precio:,.2f}")     # con separador de miles
print(f"{0.256:.1%}")       # como porcentaje

Más operaciones

print("Py" in "Python")
print("java" in "Python")
print("-".join(["a", "b", "c"]))     # une una lista con un separador
print("Ja" * 3)                      # repetir texto
palabra = "Python"
try:
    palabra[0] = "J"
except TypeError as error:
    print("Error:", error)

palabra = "J" + palabra[1:]   # en su lugar, se crea un texto nuevo
print(palabra)

Los textos son inmutables: no se pueden modificar letra por letra. Cada método devuelve un texto nuevo y deja el original intacto.

Tu turno Un usuario escribió su correo así: " Ana.Lopez@Correo.COM ". Límpialo (sin espacios y en minúsculas), extrae el nombre de usuario (lo que va antes de la @) y salúdalo.
Ver una pista

Encadena métodos: .strip().lower(). Luego .split("@") te da una lista con dos partes; la primera es [0].

Ver solución
email = "  Ana.Lopez@Correo.COM "
limpio = email.strip().lower()
usuario = limpio.split("@")[0]
print(limpio)
print(usuario)
print(f"Bienvenida, {usuario.replace('.', ' ').title()}")
Comprueba

¿Qué da "Python"[1:3]?

BásicoLección 4

Entrada y salida

Objetivo: pedirle datos al usuario y mostrar resultados bien presentados.

input() muestra una pregunta, espera a que el usuario escriba algo y te lo devuelve.

nombre = input("¿Cómo te llamas? ")
print(f"Hola, {nombre}. ¡Bienvenido a Python!")
input() en esta páginaAquí no hay un teclado esperando, así que las respuestas se escriben antes en el cuadro amarillo Entradas, una por línea. Cámbialas y vuelve a ejecutar. En Colab o en tu computadora, Python te las pedirá en el momento.

input() siempre devuelve texto

edad = int(input("¿Cuántos años tienes? "))
print(f"El próximo año tendrás {edad + 1}")

Si no conviertes la respuesta, pasa esto:

edad = input("¿Cuántos años tienes? ")
print(edad + 1)

Para Python, "20" es texto y no se puede sumar con el número 1. La solución es la del ejemplo anterior: int(input(...)) o float(input(...)).

Opciones de print()

print("a", "b", "c")
print("a", "b", "c", sep="-")     # sep: qué poner entre los valores
print("Sin salto", end=" ")       # end: qué poner al final (por defecto, un salto)
print("de línea")
Tu turno Pide dos números y muestra su suma y su promedio.
Ver solución
a = float(input("Primer número: "))
b = float(input("Segundo número: "))
print(f"Suma: {a + b}")
print(f"Promedio: {(a + b) / 2}")
Comprueba

El usuario escribe 5 en x = input(). ¿Qué da x * 2?

BásicoLección 5

Condicionales: tomar decisiones

Objetivo: que tu programa haga cosas distintas según la situación.

temperatura = 30

if temperatura > 25:
    print("Hace calor")
    print("Lleva agua")
print("Esto se imprime siempre")
La sangría importaLas líneas que pertenecen al if van con 4 espacios al inicio, después de los dos puntos :. Así sabe Python qué está “dentro” de la condición. Si olvidas los espacios o los dos puntos, verás un IndentationError o un SyntaxError.

if / else

edad = 15

if edad >= 18:
    print("Puedes votar")
else:
    print(f"Te faltan {18 - edad} años para votar")

Varias opciones con elif

Python revisa las condiciones de arriba hacia abajo y ejecuta solo la primera que se cumple.

nota = 7.5

if nota >= 9:
    print("Excelente")
elif nota >= 7:
    print("Bien")
elif nota >= 6:
    print("Aprobado")
else:
    print("Reprobado")

Prueba con Editar: cambia la nota a 9.5, a 6 y a 3, y ejecuta cada vez.

Atajos útiles

edad = 20
estado = "mayor de edad" if edad >= 18 else "menor de edad"
print(estado)

carrito = []
if not carrito:            # una lista vacía cuenta como False
    print("El carrito está vacío")

match: elegir entre muchos casos

dia = "sábado"

match dia:
    case "sábado" | "domingo":
        print("Fin de semana")
    case "lunes":
        print("Inicio de semana")
    case _:                       # _ significa "cualquier otro caso"
        print("Día laborable")
Tu turno Un año es bisiesto si es divisible entre 4, excepto los divisibles entre 100, que solo son bisiestos si también son divisibles entre 400. Escribe el código que lo decida. Prueba con 2024, 1900 y 2000.
Ver una pista

“Divisible entre 4” es año % 4 == 0. Combina las condiciones con and, or y paréntesis.

Ver solución
año = 2024

if (año % 4 == 0 and año % 100 != 0) or año % 400 == 0:
    print(f"{año} es bisiesto")
else:
    print(f"{año} no es bisiesto")

1900 no es bisiesto y 2000 sí lo es.

Comprueba

En el ejemplo de elif, si nota = 9.5, ¿qué se imprime?

BásicoLección 6

Bucles: repetir sin copiar y pegar

Objetivo: repetir instrucciones con for y while.

for: recorrer una colección

frutas = ["manzana", "pera", "uva"]

for fruta in frutas:
    print(f"Me gusta la {fruta}")

range(): contar

for i in range(5):          # 0, 1, 2, 3, 4
    print(i, end=" ")
print()
print(list(range(2, 11, 2)))  # de 2 a 10, de 2 en 2

range(5) da 0, 1, 2, 3 y 4: cinco números, empezando en 0 y sin incluir el 5.

Acumular resultados

total = 0
for n in range(1, 101):
    total += n
print(f"La suma de 1 a 100 es {total}")

for i in range(1, 6):
    print(f"7 x {i} = {7 * i}")

while: repetir mientras algo se cumpla

cuenta = 5
while cuenta > 0:
    print(cuenta)
    cuenta -= 1
print("¡Despegue!")
Bucle infinitoSi la condición de un while nunca se vuelve falsa, el bucle no termina nunca. Aquí, cuenta -= 1 evita eso. Si te pasa en esta página, no te preocupes: el programa se detiene solo después de 10 segundos.

break y continue

for n in range(1, 11):
    if n % 2 == 0:
        continue        # salta al siguiente número
    if n > 7:
        break           # termina el bucle
    print(n)

Un juego: adivina el número

secreto = 37
intentos = 0

while True:
    intento = int(input("Adivina el número (1-100): "))
    intentos += 1
    if intento < secreto:
        print("Más alto")
    elif intento > secreto:
        print("Más bajo")
    else:
        print(f"¡Correcto! Lo lograste en {intentos} intentos")
        break

Cambia las Entradas para probar otros intentos. while True repite para siempre hasta que un break lo detiene.

Bucles dentro de bucles

for i in range(1, 4):
    for j in range(1, 4):
        print(i * j, end="\t")
    print()
Tu turno: FizzBuzz Un clásico de las entrevistas de trabajo. Imprime los números del 1 al 15, pero escribe “Fizz” en lugar de los múltiplos de 3, “Buzz” en lugar de los múltiplos de 5 y “FizzBuzz” en lugar de los múltiplos de ambos.
Ver una pista

Revisa primero el caso de “ambos” (n % 15 == 0). Si lo revisas al final, nunca llegará a ejecutarse.

Ver solución
for n in range(1, 16):
    if n % 15 == 0:
        print("FizzBuzz")
    elif n % 3 == 0:
        print("Fizz")
    elif n % 5 == 0:
        print("Buzz")
    else:
        print(n)
Comprueba

¿Cuántas veces se repite for i in range(1, 4):?

IntermedioLección 7

Listas

Objetivo: guardar muchos valores en orden y trabajar con ellos.

numeros = [10, 20, 30, 40, 50]
print(numeros[0], numeros[-1])
print(numeros[1:3])
print(len(numeros), sum(numeros), min(numeros), max(numeros))

Modificar una lista

compras = ["pan", "leche"]
compras.append("huevos")      # agrega al final
compras.insert(0, "café")     # agrega en una posición
compras.remove("leche")       # quita por valor
ultimo = compras.pop()        # quita y devuelve el último
compras[0] = "té"             # reemplaza
print(compras)
print(ultimo)
print("pan" in compras)

Ordenar y buscar

nums = [5, 2, 8, 1, 9]
print(sorted(nums))                 # devuelve una lista nueva ordenada
print(nums)                         # la original no cambió
nums.sort(reverse=True)             # ordena la lista misma, de mayor a menor
print(nums)
print(nums.index(8), nums.count(5))

sorted(lista) devuelve una lista nueva; lista.sort() cambia la lista original y no devuelve nada.

La trampa de la copia

a = [1, 2, 3]
b = a            # b NO es una copia: es otro nombre para la misma lista
b.append(4)
print(a)

c = a.copy()     # copia de verdad
c.append(99)
print(a, c)
Analogíab = a no fotocopia la lista: le pone una segunda etiqueta a la misma caja. Lo que hagas con b le pasa a a. Para tener otra caja, usa .copy().

Comprensiones de lista

Una forma corta de crear una lista a partir de otra. Se lee: “dame esto por cada elemento, si cumple esta condición”.

cuadrados = [x ** 2 for x in range(1, 6)]
pares = [x for x in range(10) if x % 2 == 0]
nombres = ["ana", "luis", "marta"]
print(cuadrados)
print(pares)
print([n.capitalize() for n in nombres])

Listas de listas

matriz = [[1, 2, 3],
          [4, 5, 6]]
print(matriz[1])       # segunda fila
print(matriz[1][2])    # fila 1, columna 2
Tu turno Con las temperaturas de una semana, [22.5, 27.1, 19.8, 30.2, 25.0, 28.4, 21.3], calcula el promedio (con 1 decimal) y la máxima, y haz una lista con las mayores de 25°.
Ver solución
temperaturas = [22.5, 27.1, 19.8, 30.2, 25.0, 28.4, 21.3]
promedio = sum(temperaturas) / len(temperaturas)
calurosos = [t for t in temperaturas if t > 25]
print(f"Promedio: {promedio:.1f}")
print(f"Máxima: {max(temperaturas)}")
print(f"Días de más de 25°: {calurosos}")
Comprueba

Si x = [1, 2] y ejecutas x.append(3), ¿cuánto vale x?

IntermedioLección 8

Tuplas y conjuntos

Objetivo: conocer dos colecciones más y saber cuándo conviene cada una.

Tuplas: listas que no cambian

punto = (3, 4)
x, y = punto              # desempaquetar
print(x, y)

try:
    punto[0] = 10
except TypeError as error:
    print("Error:", error)

a, b = 1, 2
a, b = b, a               # intercambiar valores en una línea
print(a, b)

Usa tuplas para datos que van juntos y no deben modificarse, como unas coordenadas o una fecha.

Conjuntos (sets): sin repetidos

numeros = [1, 2, 2, 3, 3, 3, 4]
print(set(numeros))            # elimina los repetidos
print(len(set(numeros)))

A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
print(A | B)    # unión: en A o en B
print(A & B)    # intersección: en ambos
print(A - B)    # diferencia: en A pero no en B
Ojo con el ordenUn conjunto no guarda un orden. Si lo imprimes, los elementos pueden salir en cualquier orden; usa sorted() si necesitas verlos ordenados.
ColecciónSe escribe¿Ordenada?¿Modificable?¿Repetidos?
Lista[1, 2]SíSíSí
Tupla(1, 2)SíNoSí
Conjunto{1, 2}NoSíNo
Diccionario{"a": 1}Sí (por orden de inserción)SíClaves no
Tu turno Tienes dos listas de alumnos: los del curso de Python y los de Excel. ¿Quiénes están en ambos cursos? ¿Quiénes solo en Python?
Ver solución
python = ["Ana", "Luis", "Marta", "Pedro"]
excel = ["Luis", "Sofía", "Pedro", "Diego"]
print(sorted(set(python) & set(excel)))   # en ambos cursos
print(sorted(set(python) - set(excel)))   # solo en Python
Comprueba

¿Qué da len({1, 1, 2})?

IntermedioLección 9

Diccionarios

Objetivo: guardar información en pares clave → valor, como una ficha.

AnalogíaComo un diccionario de verdad: buscas una palabra (la clave) y obtienes su definición (el valor). No buscas por posición, sino por nombre.
persona = {"nombre": "Ana", "edad": 20, "ciudad": "Lima"}

print(persona["nombre"])
persona["edad"] = 21                 # modificar
persona["email"] = "ana@mail.com"    # agregar
del persona["ciudad"]                # eliminar
print(persona)
print(len(persona), "email" in persona)

Leer sin errores con get()

print(persona.get("telefono", "no registrado"))   # con valor por defecto

try:
    print(persona["telefono"])
except KeyError as error:
    print("No existe la clave", error)

Recorrer un diccionario

for clave, valor in persona.items():
    print(f"{clave}: {valor}")

print(list(persona.keys()))
print(list(persona.values()))

Patrón clásico: contar

texto = "el perro y el gato y el loro"
conteo = {}
for palabra in texto.split():
    conteo[palabra] = conteo.get(palabra, 0) + 1
print(conteo)

Listas de diccionarios: como una tabla

estudiantes = [
    {"nombre": "Ana", "nota": 8.5},
    {"nombre": "Luis", "nota": 6.0},
    {"nombre": "Marta", "nota": 9.2},
]
for e in estudiantes:
    estado = "aprobado" if e["nota"] >= 7 else "debe mejorar"
    print(f"{e['nombre']:<6} {e['nota']:>4}  {estado}")

En una f-string, :<6 alinea a la izquierda en 6 espacios y :>4 alinea a la derecha en 4.

Tu turno Tienes el inventario de una papelería. Se vendieron 5 lápices: réstalos y luego muestra qué productos tienen menos de 5 unidades.
Ver solución
inventario = {"lápiz": 12, "cuaderno": 3, "borrador": 8, "regla": 2}

inventario["lápiz"] -= 5          # se vendieron 5 lápices
for producto, stock in inventario.items():
    if stock < 5:
        print(f"Reponer {producto}: quedan {stock}")
Comprueba

Si d = {"a": 1}, ¿qué da d.get("b", 0)?

IntermedioLección 10

Funciones

Objetivo: crear tus propias órdenes reutilizables.

Una función es un bloque de código con nombre. Lo escribes una vez y lo usas cuantas veces quieras. Se crea con def.

def saludar():
    print("¡Hola!")
    print("Bienvenido")

saludar()      # llamar a la función
saludar()

Parámetros y return

Los parámetros son los datos que la función recibe; return es el resultado que devuelve.

def area_rectangulo(base, altura):
    return base * altura

a = area_rectangulo(5, 3)
print(a)
print(area_rectangulo(2, 10) + 1)
AnalogíaUna función es como una máquina de jugos: le das fruta (los parámetros), hace su trabajo por dentro y te devuelve el jugo (el return).

Valores por defecto y argumentos con nombre

def saludar(nombre, saludo="Hola"):
    return f"¡{saludo}, {nombre}!"

print(saludar("Ana"))
print(saludar("Luis", "Buenos días"))
print(saludar(saludo="Qué tal", nombre="Marta"))   # argumentos con nombre

Devolver varios valores

def resumen(numeros):
    """Devuelve el mínimo, el máximo y el promedio de una lista."""
    return min(numeros), max(numeros), sum(numeros) / len(numeros)

menor, mayor, promedio = resumen([4, 8, 15, 16, 23, 42])
print(menor, mayor, promedio)
print(resumen.__doc__)

El texto entre triples comillas al inicio es la docstring: documenta qué hace la función.

Lo de adentro se queda adentro

x = 10

def cambiar():
    x = 5              # esta x es local: solo existe dentro de la función
    print("dentro:", x)

cambiar()
print("fuera:", x)

print no es lo mismo que return

def con_print(n):
    print(n * 2)

def con_return(n):
    return n * 2

resultado1 = con_print(5)
resultado2 = con_return(5)
print(resultado1, resultado2)

con_print muestra el 10 en pantalla, pero no devuelve nada (None). Si necesitas usar el resultado después, usa return.

Tu turno Escribe es_primo(n), que devuelva True si n es primo (solo se divide entre 1 y sí mismo). Úsala para listar los primos del 1 al 30.
Ver una pista

Prueba dividir n entre cada número desde 2. Si alguna división da resto 0, no es primo. Basta con probar hasta la raíz cuadrada de n.

Ver solución
def es_primo(n):
    if n < 2:
        return False
    for divisor in range(2, int(n ** 0.5) + 1):
        if n % divisor == 0:
            return False
    return True

print(es_primo(7), es_primo(10))
print([n for n in range(1, 31) if es_primo(n)])
Comprueba

¿Qué devuelve una función que no tiene return?

IntermedioLección 11

Errores y excepciones

Objetivo: que tu programa no se caiga cuando algo sale mal.

ErrorCuándo aparece
SyntaxErrorEscribiste algo que Python no entiende: falta un paréntesis, unas comillas o los dos puntos
NameErrorUsas una variable que no existe (a menudo, un error de escritura)
TypeErrorMezclas tipos que no combinan, como texto + número
ValueErrorEl tipo es correcto, pero el valor no sirve: int("abc")
IndexError / KeyErrorPides una posición de lista o una clave de diccionario que no existe
ZeroDivisionErrorDivides entre cero

try / except: intentar y atrapar

texto = "abc"
try:
    numero = int(texto)
    print("Número:", numero)
except ValueError:
    print(f"'{texto}' no es un número")
def dividir(a, b):
    try:
        resultado = a / b
    except ZeroDivisionError:
        return "No se puede dividir entre cero"
    except TypeError:
        return "Solo se pueden dividir números"
    else:
        return resultado         # solo si no hubo error
    finally:
        print("(división intentada)")   # se ejecuta siempre

print(dividir(10, 4))
print(dividir(10, 0))
print(dividir(10, "dos"))

Validar lo que escribe el usuario

while True:
    try:
        edad = int(input("Tu edad: "))
        break
    except ValueError:
        print("Escribe un número entero, por ejemplo 20")
print(f"Edad registrada: {edad}")

Lanzar tus propios errores con raise

def retirar(saldo, monto):
    if monto <= 0:
        raise ValueError("El monto debe ser positivo")
    if monto > saldo:
        raise ValueError(f"Saldo insuficiente: tienes {saldo}")
    return saldo - monto

print(retirar(100, 30))
try:
    retirar(100, 500)
except ValueError as error:
    print("No se pudo retirar:", error)
No atrapes todo a ciegasUn except: sin tipo atrapa cualquier error, incluso los que no esperabas, y los esconde. Indica siempre qué error esperas: except ValueError:.
Tu turno Tienes la lista ["10", "x", "5", "3.5", ""]. Suma los valores que sean números válidos y guarda en otra lista los que no lo sean.
Ver solución
datos = ["10", "x", "5", "3.5", ""]
total = 0
invalidos = []

for d in datos:
    try:
        total += float(d)
    except ValueError:
        invalidos.append(d)

print(f"Total: {total}")
print(f"Inválidos: {invalidos}")
Comprueba

¿Cuándo se ejecuta el bloque finally?

IntermedioLección 12

Archivos

Objetivo: guardar y leer información para que no se pierda al cerrar el programa.

Ejecuta estos ejemplos en orden: cada uno usa el archivo que creó el anterior.

Escribir

with open("notas.txt", "w", encoding="utf-8") as archivo:
    archivo.write("Ana,8.5\n")
    archivo.write("Luis,6.0\n")
    archivo.write("Marta,9.2\n")
print("Archivo guardado")

with abre el archivo y lo cierra solo al terminar. "w" significa escribir (borra lo que había), y \n es un salto de línea. Usa siempre encoding="utf-8" para que las tildes y la ñ se guarden bien.

Leer

with open("notas.txt", encoding="utf-8") as archivo:
    contenido = archivo.read()
print(contenido)
with open("notas.txt", encoding="utf-8") as archivo:
    for linea in archivo:
        nombre, nota = linea.strip().split(",")
        print(f"{nombre} sacó {float(nota)}")

Agregar al final

with open("notas.txt", "a", encoding="utf-8") as archivo:   # "a" = agregar al final
    archivo.write("Pedro,7.0\n")

with open("notas.txt", encoding="utf-8") as archivo:
    print(len(archivo.readlines()), "líneas")

JSON: guardar listas y diccionarios

import json

config = {"usuario": "ana", "tema": "oscuro", "favoritos": [3, 7, 12]}

with open("config.json", "w", encoding="utf-8") as f:
    json.dump(config, f, ensure_ascii=False, indent=2)

with open("config.json", encoding="utf-8") as f:
    cargado = json.load(f)
print(cargado["favoritos"])
print(cargado == config)

CSV: datos en columnas

import csv

with open("notas.txt", encoding="utf-8") as f:
    lector = csv.reader(f)
    filas = [(nombre, float(nota)) for nombre, nota in lector]

mejor = max(filas, key=lambda fila: fila[1])
print(filas)
print("Mejor nota:", mejor)

Cuando el archivo no existe

try:
    with open("no_existe.txt", encoding="utf-8") as f:
        print(f.read())
except FileNotFoundError:
    print("El archivo no existe. Revisa el nombre y la carpeta.")
Archivos en esta páginaLos archivos que creas aquí viven en la memoria del navegador y se borran al recargar la página. En tu computadora se guardan en la carpeta desde donde ejecutas el programa.
Tu turno Lee notas.txt y calcula cuántos estudiantes hay y su promedio, con 2 decimales.
Ver solución
with open("notas.txt", encoding="utf-8") as f:
    notas = [float(linea.strip().split(",")[1]) for linea in f]

print(f"{len(notas)} estudiantes, promedio {sum(notas) / len(notas):.2f}")
Comprueba

Quieres añadir una línea a un archivo sin borrar lo que ya tiene. ¿Qué modo usas?

IntermedioLección 13

Módulos y librerías

Objetivo: usar código que ya escribieron otros y organizar el tuyo en archivos.

Python viene con una “biblioteca estándar” enorme. Para usar una parte, la importas con import.

import math

print(math.sqrt(16))
print(math.pi)
print(math.floor(3.7), math.ceil(3.2))   # redondear hacia abajo / arriba
from math import sqrt, pi     # importar solo lo que necesitas
print(sqrt(25), round(pi, 2))

import datetime as dt          # importar con un nombre corto
print(dt.date(2026, 10, 7))

Números al azar

import random

random.seed(42)    # fija la "semilla": así obtienes siempre los mismos resultados
print(random.randint(1, 6))
print(random.choice(["piedra", "papel", "tijera"]))
cartas = [1, 2, 3, 4, 5]
random.shuffle(cartas)
print(cartas)

Sin random.seed() obtendrías resultados distintos cada vez. La semilla sirve para que un experimento se pueda repetir.

Fechas

from datetime import date, timedelta

hoy = date(2026, 10, 7)
print(hoy + timedelta(days=30))
print(hoy.strftime("%d/%m/%Y"))
print((date(2026, 12, 25) - hoy).days, "días para Navidad")

Tus propios módulos

Cualquier archivo .py es un módulo. Si tienes estos dos archivos en la misma carpeta:

# archivo: utilidades.py
def celsius_a_fahrenheit(c):
    return c * 9 / 5 + 32
# archivo: main.py (en la misma carpeta)
import utilidades

print(utilidades.celsius_a_fahrenheit(25))

Librerías externas con pip

Hay cientos de miles de librerías gratuitas en pypi.org. Se instalan desde la terminal (en Colab, con !pip install ...):

pip install requests

Algunas muy populares: requests (internet), pandas (datos en tablas), matplotlib (gráficos), flask (páginas web) y pygame (videojuegos).

Tu turno Simula 600 lanzamientos de un dado y cuenta cuántas veces sale cada cara. Muestra una barra de # por cada 10 veces.
Ver una pista

Usa un diccionario para contar (como en la lección 9) y random.randint(1, 6) dentro de un for. "#" * 5 da #####.

Ver solución
import random

random.seed(1)
conteo = {}
for _ in range(600):
    cara = random.randint(1, 6)
    conteo[cara] = conteo.get(cara, 0) + 1

for cara in sorted(conteo):
    print(cara, "#" * (conteo[cara] // 10), conteo[cara])

Cada cara debería salir unas 100 veces. Con más lanzamientos, los números se parecen cada vez más.

Comprueba

Después de from math import sqrt, ¿cómo calculas la raíz de 9?

AvanzadoLección 14

Clases y objetos

Objetivo: crear tus propios tipos de datos que junten información y comportamiento.

AnalogíaUna clase es el plano de una casa; cada objeto es una casa construida con ese plano. Todas tienen la misma forma, pero cada una tiene su propio color y sus propios dueños.
class Perro:
    def __init__(self, nombre, edad):    # se ejecuta al crear el objeto
        self.nombre = nombre             # atributos: datos del objeto
        self.edad = edad

    def ladrar(self):                    # método: algo que el objeto sabe hacer
        return f"{self.nombre} dice: ¡Guau!"

firulais = Perro("Firulais", 3)
toby = Perro("Toby", 5)
print(firulais.ladrar())
print(toby.nombre, toby.edad)
  • __init__ se ejecuta automáticamente al crear el objeto y prepara sus datos.
  • self es “este objeto en particular”. Por eso self.nombre es el nombre de cada perro.
  • Los atributos son los datos (nombre, edad) y los métodos son las funciones de la clase (ladrar).

Un ejemplo completo: una cuenta bancaria

class CuentaBancaria:
    def __init__(self, titular, saldo=0):
        self.titular = titular
        self.saldo = saldo

    def depositar(self, monto):
        if monto <= 0:
            raise ValueError("El depósito debe ser positivo")
        self.saldo += monto

    def retirar(self, monto):
        if monto > self.saldo:
            raise ValueError("Saldo insuficiente")
        self.saldo -= monto

    def __str__(self):                  # cómo se ve al imprimirlo
        return f"Cuenta de {self.titular}: ${self.saldo:,.2f}"

cuenta = CuentaBancaria("Ana", 100)
cuenta.depositar(50)
cuenta.retirar(30)
print(cuenta)
try:
    cuenta.retirar(1000)
except ValueError as error:
    print("Error:", error)

La clase protege sus reglas: no se puede retirar más de lo que hay. __str__ define cómo se ve el objeto al imprimirlo.

Herencia

Una clase puede heredar de otra: recibe todo lo que la otra tiene y cambia solo lo necesario.

class Animal:
    def __init__(self, nombre):
        self.nombre = nombre

    def hablar(self):
        return "..."

    def presentarse(self):
        return f"Soy {self.nombre} y digo {self.hablar()}"

class Gato(Animal):           # Gato hereda todo de Animal
    def hablar(self):         # y redefine este método
        return "miau"

class Vaca(Animal):
    def hablar(self):
        return "muu"

for animal in [Gato("Michi"), Vaca("Lola"), Animal("Algo")]:
    print(animal.presentarse())
Tu turno Crea la clase Rectangulo con base y altura, y los métodos area(), perimetro() y es_cuadrado().
Ver solución
class Rectangulo:
    def __init__(self, base, altura):
        self.base = base
        self.altura = altura

    def area(self):
        return self.base * self.altura

    def perimetro(self):
        return 2 * (self.base + self.altura)

    def es_cuadrado(self):
        return self.base == self.altura

r = Rectangulo(4, 6)
c = Rectangulo(5, 5)
print(r.area(), r.perimetro(), r.es_cuadrado())
print(c.area(), c.perimetro(), c.es_cuadrado())
Comprueba

¿Cuándo se ejecuta __init__?

AvanzadoLección 15

Herramientas pythónicas

Objetivo: escribir código más corto y claro, como lo escribe la gente con experiencia en Python.

enumerate y zip

frutas = ["manzana", "pera", "uva"]
for i, fruta in enumerate(frutas, start=1):
    print(i, fruta)

nombres = ["Ana", "Luis", "Marta"]
notas = [8.5, 6.0, 9.2]
for nombre, nota in zip(nombres, notas):
    print(f"{nombre}: {nota}")

Comprensiones de diccionario y de conjunto

precios = {"pan": 1.2, "leche": 0.9, "queso": 4.5}
con_iva = {producto: round(p * 1.18, 2) for producto, p in precios.items()}
print(con_iva)
print({len(p) for p in ["sol", "luna", "mar", "cielo"]})   # comprensión de conjunto

lambda, sorted, map y filter

lambda crea una función pequeña de una sola línea, sin nombre. Es muy útil para decirle a sorted o a max según qué deben ordenar.

personas = [("Ana", 25), ("Luis", 19), ("Marta", 32)]

print(sorted(personas, key=lambda p: p[1]))               # ordenar por edad
print(max(personas, key=lambda p: p[1]))
print(list(map(lambda p: p[0].upper(), personas)))
print(list(filter(lambda p: p[1] >= 21, personas)))

any y all

notas = [7.5, 8.2, 6.1, 9.0]
print(all(n >= 6 for n in notas))    # ¿todos aprobaron?
print(any(n >= 9 for n in notas))    # ¿alguien sacó 9 o más?

*args y **kwargs

def promedio(*numeros):          # *: acepta cualquier cantidad de argumentos
    return sum(numeros) / len(numeros)

def ficha(**datos):              # **: acepta argumentos con nombre libres
    for clave, valor in datos.items():
        print(f"{clave} = {valor}")

print(promedio(4, 8, 6))
print(promedio(10, 20))
ficha(nombre="Ana", ciudad="Lima", edad=20)
Tu turno Con ["python", "es", "un", "lenguaje", "muy", "versátil"], obtén las palabras de más de 3 letras ordenadas de más larga a más corta, y un diccionario con la longitud de cada palabra.
Ver solución
palabras = ["python", "es", "un", "lenguaje", "muy", "versátil"]
largas = sorted([p for p in palabras if len(p) > 3], key=len, reverse=True)
longitudes = {p: len(p) for p in palabras}
print(largas)
print(longitudes)
Comprueba

¿Qué da list(zip([1, 2], ["a", "b"]))?

AvanzadoLección 16

Iteradores, generadores y decoradores

Objetivo: entender cómo funciona for por dentro y conocer dos herramientas avanzadas muy usadas.

Iteradores

Cuando haces un for, Python pide los elementos uno por uno con next(). Puedes hacerlo a mano:

colores = ["rojo", "verde", "azul"]
it = iter(colores)
print(next(it))
print(next(it))
print(next(it))

Generadores: valores bajo demanda

Una función con yield no devuelve todo de golpe: entrega un valor, se pausa y continúa cuando le piden el siguiente.

def cuenta_regresiva(n):
    while n > 0:
        yield n          # entrega un valor y se pausa hasta que pidan el siguiente
        n -= 1

for x in cuenta_regresiva(3):
    print(x)
print(list(cuenta_regresiva(5)))
def fibonacci():
    a, b = 0, 1
    while True:          # infinito, pero solo calcula lo que se pide
        yield a
        a, b = b, a + b

fib = fibonacci()
print([next(fib) for _ in range(10)])

# expresión generadora: como una comprensión, pero sin guardar la lista en memoria
print(sum(x ** 2 for x in range(1_000_000)))
AnalogíaUna lista es una caja con todas las galletas ya horneadas. Un generador es un horno que hornea una galleta cada vez que pides una: ocupa mucho menos espacio, y la serie puede ser infinita.

Decoradores: envolver funciones

Un decorador recibe una función y devuelve otra que le agrega algo, sin tocar el código original. Se aplica con @.

def anunciar(funcion):
    def envoltura(*args):
        print(f"Llamando a {funcion.__name__}{args}")
        resultado = funcion(*args)
        print(f"Resultado: {resultado}")
        return resultado
    return envoltura

@anunciar                  # equivale a: sumar = anunciar(sumar)
def sumar(a, b):
    return a + b

sumar(3, 4)

Los verás mucho en librerías web como Flask (@app.route("/")) y en pruebas automáticas.

Tu turno Escribe el generador pares(limite), que entregue los números pares desde 0 hasta limite. Muestra los pares hasta 10 y suma los pares hasta 100.
Ver solución
def pares(limite):
    n = 0
    while n <= limite:
        yield n
        n += 2

print(list(pares(10)))
print(sum(pares(100)))
Comprueba

¿Qué palabra convierte una función en generador?

AvanzadoLección 17

Buenas prácticas

Objetivo: escribir código que otras personas (y tú en seis meses) puedan entender y mantener.

Estilo PEP 8

  • Variables y funciones en minúsculas con guion bajo: precio_total, calcular_iva().
  • Clases con mayúscula inicial: CuentaBancaria.
  • Sangría de 4 espacios y líneas de menos de 80 caracteres, más o menos.
  • Nombres que expliquen qué guardan: edad_cliente en lugar de x.

Anotaciones de tipo

Indican qué tipos espera y devuelve una función. Python no las obliga, pero tu editor las usa para avisarte de errores.

def promedio(numeros: list[float]) -> float:
    """Calcula el promedio de una lista de números."""
    if not numeros:
        raise ValueError("La lista está vacía")
    return sum(numeros) / len(numeros)

print(promedio([7.5, 8.0, 9.5]))

Depurar con f-strings

x = 5
lista = [1, 2, 3]
print(f"{x=}")           # muestra el nombre y el valor: útil para depurar
print(f"{len(lista)=}")

Probar tu código

def es_palindromo(texto):
    limpio = texto.lower().replace(" ", "")
    return limpio == limpio[::-1]

# pruebas rápidas: si alguna falla, Python lo avisa con un AssertionError
assert es_palindromo("Anita lava la tina")
assert es_palindromo("oso")
assert not es_palindromo("python")
print("Todas las pruebas pasaron")

Cuando tus proyectos crezcan, usa pytest: guardas funciones de prueba como estas en archivos test_*.py y las ejecutas todas con el comando pytest.

El punto de entrada de un programa

def main():
    print("Programa principal")

if __name__ == "__main__":   # solo se ejecuta si corres este archivo directamente,
    main()                   # no si otro archivo lo importa

Entornos virtuales

Cada proyecto debería tener su propio entorno, con sus propias librerías, para que no choquen versiones entre proyectos:

python -m venv .venv              # crear el entorno (una vez por proyecto)
.venv\Scripts\activate            # activarlo en Windows
source .venv/bin/activate         # activarlo en Mac o Linux
pip install requests              # instalar dentro del entorno
pip freeze > requirements.txt     # guardar la lista de librerías
Comprueba

Según PEP 8, ¿cómo deberías nombrar una clase que representa un carrito de compras?

AvanzadoLección 18

Proyecto final: gestor de tareas

Objetivo: construir un programa completo que junte todo lo aprendido: clases, listas, errores, archivos y un menú interactivo. Intenta cada paso antes de abrir la solución.

El programaUna lista de pendientes en la consola. El usuario puede ver sus tareas, agregar nuevas y marcarlas como hechas, y todo se guarda en un archivo para la próxima vez.
Paso 1. La clase Tarea Crea una clase Tarea con un título y un estado (hecha o no). Al imprimirla debe verse como [ ] Estudiar Python o [x] Estudiar Python.
Ver solución
class Tarea:
    def __init__(self, titulo, hecha=False):
        self.titulo = titulo
        self.hecha = hecha

    def __str__(self):
        marca = "x" if self.hecha else " "
        return f"[{marca}] {self.titulo}"

t = Tarea("Estudiar Python")
print(t)
t.hecha = True
print(t)
Paso 2. El gestor Crea GestorTareas, que guarde una lista de tareas y tenga los métodos agregar, completar, listar y pendientes. Valida los datos con raise.
Ver solución
class GestorTareas:
    def __init__(self):
        self.tareas = []

    def agregar(self, titulo):
        titulo = titulo.strip()
        if not titulo:
            raise ValueError("El título no puede estar vacío")
        self.tareas.append(Tarea(titulo))

    def completar(self, numero):
        if not 1 <= numero <= len(self.tareas):
            raise ValueError(f"No existe la tarea {numero}")
        self.tareas[numero - 1].hecha = True

    def listar(self):
        if not self.tareas:
            print("No hay tareas")
        for i, tarea in enumerate(self.tareas, start=1):
            print(f"{i}. {tarea}")

    def pendientes(self):
        return sum(1 for t in self.tareas if not t.hecha)

gestor = GestorTareas()
gestor.agregar("Estudiar Python")
gestor.agregar("Hacer ejercicio")
gestor.completar(1)
gestor.listar()
print("Pendientes:", gestor.pendientes())
Paso 3. Guardar y cargar Escribe guardar(gestor) y cargar() usando un archivo JSON. Si el archivo no existe, empieza con la lista vacía.
Ver solución
import json

def guardar(gestor, ruta="tareas.json"):
    datos = [{"titulo": t.titulo, "hecha": t.hecha} for t in gestor.tareas]
    with open(ruta, "w", encoding="utf-8") as f:
        json.dump(datos, f, ensure_ascii=False, indent=2)

def cargar(ruta="tareas.json"):
    gestor = GestorTareas()
    try:
        with open(ruta, encoding="utf-8") as f:
            for d in json.load(f):
                gestor.tareas.append(Tarea(d["titulo"], d["hecha"]))
    except FileNotFoundError:
        pass                      # primera vez: empezamos sin tareas
    return gestor

guardar(gestor)
otro = cargar()
otro.listar()
Paso 4. El menú Une todo con un menú que se repita hasta que el usuario elija salir. Usa try/except para que un error no cierre el programa.
Ver solución
def menu():
    gestor = cargar()
    while True:
        print("\n1) Ver  2) Agregar  3) Completar  4) Salir")
        opcion = input("Elige una opción: ").strip()
        try:
            if opcion == "1":
                gestor.listar()
            elif opcion == "2":
                gestor.agregar(input("Título: "))
                print("Tarea agregada")
            elif opcion == "3":
                gestor.completar(int(input("Número de tarea: ")))
                print("¡Bien hecho!")
            elif opcion == "4":
                guardar(gestor)
                print(f"Guardado. Tareas pendientes: {gestor.pendientes()}")
                break
            else:
                print("Opción no válida")
        except ValueError as error:
            print("Error:", error)

menu()

Cambia las Entradas para probar otros caminos. Fíjate en que el número 7 no cerró el programa: mostró un error amable y siguió funcionando.

Retos extra Si terminaste, mejora tu programa: agrega una opción para borrar tareas, una fecha límite con datetime o una prioridad (alta, media, baja), y muestra las tareas ordenadas con sorted(..., key=...).
Práctica libre

Consola libre

Escribe cualquier programa y ejecútalo. Comparte la memoria con los ejemplos de la guía, así que puedes usar las variables y funciones que ya creaste.

# Escribe aquí tu código
nombre = input("¿Qué quieres aprender? ")
for i in range(3):
    print(f"¡Voy a aprender {nombre}!")
Referencia

Chuleta

Lo esencial de la guía en una tabla, para consultarla mientras programas.

Para…CódigoLección
Mostrar algoprint("hola", x)0
Crear una variableedad = 201
Convertir tiposint(), float(), str()1
División entera y resto7 // 2, 7 % 22
Insertar variables en textof"Hola {nombre}", f"{x:.2f}"3
Pedir un datoint(input("Edad: "))4
Decidirif ...: elif ...: else:5
Repetirfor x in lista:, for i in range(n):, while cond:6
Listas.append(), .remove(), sorted(), len()7
Comprensión de lista[x * 2 for x in lista if x > 0]7
Quitar repetidosset(lista)8
Diccionariosd["clave"], d.get("clave", 0), d.items()9
Crear una funcióndef nombre(param): return ...10
Manejar errorestry: ... except ValueError: ...11
Leer un archivowith open("a.txt", encoding="utf-8") as f:12
Importarimport math, from random import randint13
Crear una claseclass Nombre: def __init__(self, ...):14
Numerar y emparejarenumerate(lista), zip(a, b)15
Generadordef gen(): yield valor16

Para seguir aprendiendo

  • Tutorial oficial de Python en español: completo y gratuito.
  • Codewars y Exercism: ejercicios cortos con niveles de dificultad.
  • Elige un proyecto que te importe: automatizar renombrar archivos, un bot para tu grupo, un juego con pygame o una página con Flask. Se aprende más construyendo que leyendo.

Los resultados de cada ejemplo se obtuvieron ejecutándolos con Python 3.14. El botón ▶ Ejecutar usa Pyodide, Python 3.14 dentro del navegador.