# =============================================================================
# RECORRIDO DE CADENAS EN PYTHON
# =============================================================================
# Una cadena (string) es una secuencia de caracteres: letras, espacios, comas...
# Python nos permite recorrer esa secuencia carácter a carácter de varias formas.
#
# En este programa veremos:
# 1. Tres maneras distintas de recorrer una cadena con su posición
# 2. Cómo usar esa posición para hacer cosas distintas según sea par o impar
# 3. Cómo meter todo eso en una función reutilizable
# 4. Cómo aplicar esa función a una lista de textos
#
# ¿Qué es la posición (índice)?
# Cada carácter de una cadena tiene un número de posición que empieza en 0.
#
# Cadena: H o l a q u e ...
# Posición: 0 1 2 3 4 5 6 7 ...
#
# IMPORTANTE: en Python los índices empiezan en 0, no en 1.
# =============================================================================
cadena = "Hola que tal, Python es genial"
# Declaramos la cadena con la que vamos a trabajar en los tres primeros ejemplos.
# Podría ser cualquier texto: cadena = input("Escribe algo: ")
resultado = ""
# Variable donde iremos construyendo la cadena transformada.
# Empieza vacía y le iremos añadiendo letras una a una.
# NUNCA la inicialices con otro valor o aparecerá texto extra al inicio.
# =============================================================================
# MANERA 1: CONTADOR MANUAL
# =============================================================================
# La forma más intuitiva para un principiante.
# Usamos una variable "posicion" que aumentamos nosotros a mano en cada vuelta.
# =============================================================================
posicion = 1
# Empezamos en 1 porque queremos mostrar posiciones "humanas" (del 1 en adelante).
# Nota: internamente Python usa 0, pero aquí lo mostramos desde 1 para el usuario.
for letra in cadena:
# El bucle for recorre la cadena carácter a carácter.
# En cada vuelta, "letra" toma el valor del siguiente carácter.
# Ejemplo: vuelta 1 → letra="H", vuelta 2 → letra="o", etc.
print(posicion, letra)
# Imprime la posición actual y la letra correspondiente.
# Salida ejemplo:
# 1 H
# 2 o
# 3 l
# 4 a
# 5 (el espacio también es un carácter)
posicion = posicion + 1
# Incrementamos el contador manualmente para que en la próxima vuelta
# indique la siguiente posición.
# ALTERNATIVA más corta: posicion += 1
# SIN esta línea, "posicion" siempre valdría 1 → mostraría siempre "1"
# =============================================================================
# MANERA 2: CON range() Y len()
# =============================================================================
# En lugar de recorrer las letras directamente, recorremos los números
# de posición (0, 1, 2, ...) y accedemos a cada letra por su índice.
#
# len(cadena) → devuelve el número total de caracteres de la cadena
# range(n) → genera los números 0, 1, 2, ..., n-1
# cadena[i] → accede a la letra que está en la posición i
# =============================================================================
for posicion in range(len(cadena)):
# range(len(cadena)) con nuestra cadena genera: 0, 1, 2, ..., 29
# (porque "Hola que tal, Python es genial" tiene 30 caracteres)
# En cada vuelta, "posicion" vale el índice actual (empieza en 0).
print(posicion + 1, cadena[posicion])
# cadena[posicion] → accede a la letra en esa posición.
# cadena[0] → "H"
# cadena[1] → "o"
# cadena[4] → " " (espacio)
# Sumamos +1 al mostrar para que el usuario vea 1, 2, 3... en lugar de 0, 1, 2...
#
# VENTAJA de esta manera sobre la 1: con "posicion" podemos acceder a
# la letra anterior (cadena[posicion-1]) o siguiente (cadena[posicion+1])
# =============================================================================
# MANERA 3: CON enumerate() ← LA MÁS USADA EN PYTHON
# =============================================================================
# enumerate() nos da automáticamente DOS cosas en cada vuelta:
# - La posición (índice, empezando en 0)
# - El carácter en esa posición
# Es la manera más "pythónica" (la preferida por los programadores Python).
# =============================================================================
for posicion, letra in enumerate(cadena):
# enumerate() devuelve pares (posición, carácter) en cada vuelta.
# Desglosamos ese par en dos variables: "posicion" y "letra".
# Equivale a hacer las maneras 1 y 2 a la vez, sin código extra.
# Ejemplo: vuelta 1 → posicion=0, letra="H"
# vuelta 2 → posicion=1, letra="o"
print(posicion + 1, letra)
# Mostramos posición (desde 1) y letra, igual que en las maneras anteriores.
if posicion % 2 == 0:
# El operador % calcula el RESTO de la división.
# posicion % 2 → si el resto es 0, la posición es PAR; si es 1, es IMPAR.
# Posiciones pares: 0, 2, 4, 6, 8, ... (H, l, ' ', u, ' ', t, ...)
# Posiciones impares: 1, 3, 5, 7, 9, ... (o, a, q, e, a, ...)
# RECUERDA: la posición 0 (la primera) es PAR en Python.
resultado = resultado + letra.lower()
# .lower() convierte la letra a minúscula.
# Si ya era minúscula, no cambia nada.
# La añadimos al final de "resultado".
# ALTERNATIVA más corta: resultado += letra.lower()
else:
# Si la posición es impar (resto 1)
resultado = resultado + letra.upper()
# .upper() convierte la letra a mayúscula.
# Los espacios y comas no cambian con upper() ni lower().
print(resultado)
# Muestra la cadena transformada al estilo "camello alternado":
# "Hola que tal, Python es genial"
# ↓
# "hOlA QuE TaL, pYtHoN Es gEnIaL"
# (posiciones pares en minúscula, impares en mayúscula)
# =============================================================================
# FUNCIÓN texto_camello()
# =============================================================================
# Metemos todo el proceso en una función para poder reutilizarlo con
# cualquier texto sin tener que reescribir el código.
#
# Entrada: una cadena de texto cualquiera
# Salida: la misma cadena con letras alternadas mayúscula/minúscula
#
# Ejemplo: texto_camello("hola") → "hOlA"
# =============================================================================
def texto_camello(cadena):
# "def" define la función. "cadena" es el parámetro:
# el texto que recibirá la función cuando la llamemos.
# Este "cadena" es LOCAL a la función, no tiene nada que ver
# con la variable "cadena" que declaramos arriba.
resultado = ""
# IMPORTANTE: declaramos resultado DENTRO de la función.
# Cada vez que llamemos a la función, resultado empieza vacío desde cero.
# Si estuviera fuera, las llamadas anteriores acumularían texto sobrante.
for posicion, letra in enumerate(cadena):
# Recorremos la cadena que nos han pasado como parámetro,
# obteniendo posición y letra en cada vuelta.
print(posicion + 1, letra)
# Muestra el progreso por pantalla mientras trabaja.
# En un programa real probablemente quitaríamos este print,
# ya que solo nos interesa el resultado final.
if posicion % 2 == 0:
resultado = resultado + letra.lower()
# Posición par → minúscula
else:
resultado = resultado + letra.upper()
# Posición impar → mayúscula
return resultado
# Devuelve la cadena transformada al lugar donde se llamó la función.
# Sin "return" la función haría todo el trabajo pero no compartiría el resultado.
# =============================================================================
# LLAMADAS A LA FUNCIÓN
# =============================================================================
cadena = "Hola que tal, Python es genial"
# Reasignamos la variable cadena (la anterior también valía, pero así
# queda claro con qué texto trabajamos en esta sección).
print(texto_camello("hola que tal"))
# Llamada con texto directo (literal de cadena).
# La función recibe "hola que tal" como parámetro.
# Imprime: "hOlA QuE TaL"
print(texto_camello(cadena))
# Llamada pasando una variable como argumento.
# La función recibe el contenido de "cadena": "Hola que tal, Python es genial"
# Imprime: "hOlA QuE TaL, pYtHoN Es gEnIaL"
versos = ["Vi un gato muerto", "espanzurrado en la carretera", "una gaviota acechaba", "y la tormenta tronaba"]
# Lista de cadenas. Cada elemento es una línea de un poema.
# Podría ser cualquier colección de textos: nombres, frases, párrafos...
for verso in versos:
# Recorremos la lista. En cada vuelta "verso" toma el valor de la siguiente línea.
# Vuelta 1: verso = "Vi un gato muerto"
# Vuelta 2: verso = "espanzurrado en la carretera"
# ...
print(texto_camello(verso))
# Aplicamos la función a cada verso y mostramos el resultado.
# Salida:
# "vI Un gAtO MuErTo"
# "eSpAnZuRrAdO En lA CaRrEtErA"
# "uNa gAvIoTa aCeChAbA"
# "y lA ToRmEnTa tRoNaBa"
#
# ALTERNATIVA con comprensión de listas:
# transformados = [texto_camello(v) for v in versos]
# print('\n'.join(transformados))
Mes: mayo 2026
Más repaso while
# =============================================================================
# CALCULAR LA MEDIA DE UNA SERIE DE NÚMEROS
# =============================================================================
# Este programa pide números al usuario uno a uno y los va sumando.
# Cuando el usuario introduce un 0, el programa para y calcula la media.
#
# La media es la suma de todos los números dividida entre cuántos hay.
# Ejemplo: si introduces 4, 8 y 6 → media = (4+8+6) / 3 = 6.0
#
# Interacción esperada:
# Digite un numero: 4
# Digite un numero: 8
# Digite un numero: 6
# Digite un numero: 0 ← el 0 para el bucle, no se suma
# 6.0
# =============================================================================
def calcular_media():
# Definimos la función. No recibe parámetros porque los datos
# los pedirá ella misma al usuario con input().
# Devolverá un número decimal (float) con la media calculada.
numero = float(input("Digite un numero: "))
# Pedimos el PRIMER número antes del bucle.
# Necesitamos hacerlo aquí para poder comprobar la condición del while.
# float() convierte el texto que escribe el usuario a número decimal.
# Usamos float en lugar de int para aceptar números como 3.5 o 7.8.
# PRUEBA: cambia float() por int() e intenta introducir 3.5 para ver el error.
suma = 0
# Variable acumuladora: irá sumando todos los números que introduzca el usuario.
# Siempre se inicializa a 0 antes del bucle.
# Ejemplo paso a paso con 4, 8, 6:
# Antes del bucle: suma = 0
# Tras el 4: suma = 4
# Tras el 8: suma = 12
# Tras el 6: suma = 18
contador = 0
# Variable contadora: cuenta cuántos números ha introducido el usuario.
# También se inicializa a 0. La necesitamos para dividir al calcular la media.
# Ejemplo: con 4, 8 y 6 → contador llegará a 3.
# ¡IMPORTANTE! El 0 final NO se cuenta porque para el bucle antes de sumarlo.
while numero != 0:
# El bucle se repite MIENTRAS el número introducido sea distinto de 0.
# En cuanto el usuario escribe 0, el bucle termina sin sumar ni contar ese 0.
# "!=" significa "distinto de".
# ALTERNATIVA equivalente: while not numero == 0:
# ↓ Aquí estaba el comentario "????" en el código original.
# Lo que hace este bloque es acumular el número en la suma
# y aumentar el contador en 1 por cada número válido introducido.
suma = suma + numero
# Añadimos el número actual a la suma acumulada.
# Es lo mismo que escribir: suma += numero
# Solo llegamos aquí si numero != 0, así que el 0 nunca se suma.
contador = contador + 1
# Contamos este número como válido.
# Es lo mismo que escribir: contador += 1
numero = float(input("Digite un numero: "))
# Pedimos el SIGUIENTE número al final del bucle.
# Esto sobreescribe el valor anterior de "numero".
# En la próxima comprobación del while se usará este nuevo valor.
# Si el usuario escribe 0 aquí, el while parará en su próxima vuelta.
# Cuando llegamos aquí, el bucle ya ha terminado.
# En este punto sabemos que:
# - "suma" tiene la suma de todos los números introducidos (sin el 0)
# - "contador" tiene cuántos números se introdujeron (sin el 0)
return suma / contador
# Calculamos y devolvemos la media: suma total dividida entre cuántos números hay.
# CUIDADO: si el usuario introduce 0 como primer número, contador valdrá 0
# y dividir entre 0 causará un error (ZeroDivisionError).
# MEJORA para evitar ese error:
# if contador == 0:
# return 0
# return suma / contador
# =============================================================================
# PROGRAMA PRINCIPAL
# =============================================================================
media = calcular_media()
# Llamamos a la función. Esta ejecuta todo el proceso de pedir números
# y calcular la media. El resultado que devuelve "return" se guarda aquí.
print(media)
# Mostramos la media por pantalla.
# MEJORA para que quede más claro:
# print(f"La media de los números introducidos es: {media:.2f}")
# El :.2f muestra solo 2 decimales. Ejemplo: 6.333333 → 6.33
Repaso while
# =============================================================================
# FUNCIONES CON VALIDACIÓN Y LISTAS EN PYTHON
# =============================================================================
# En este programa vamos a ver cómo crear una función que:
# 1. Pide un dato al usuario
# 2. Comprueba que el dato sea correcto (validación)
# 3. Devuelve el dato para usarlo desde fuera
#
# Después veremos TRES formas distintas de usar esa función:
# - Imprimir el resultado directamente
# - Guardarlo en una variable
# - Añadirlo a una lista
#
# Y por último, un ejemplo real: recoger las notas de un grupo de alumnos.
# =============================================================================
# =============================================================================
# DEFINICIÓN DE LA FUNCIÓN pedir_nota()
# =============================================================================
# Una función es un bloque de código con nombre que podemos reutilizar
# tantas veces como queramos sin tener que reescribirlo.
#
# Esta función:
# - No recibe ningún parámetro (los paréntesis están vacíos)
# - Se encarga de pedir una nota válida al usuario
# - Devuelve la nota una vez validada
# =============================================================================
def pedir_nota():
# "def" le dice a Python que vamos a definir una función.
# "pedir_nota" es el nombre que le damos (debe ser descriptivo).
# Los "():" al final son obligatorios aunque no haya parámetros.
# Todo lo que esté indentado (con sangría) pertenece a la función.
print("Introduce una nota entre 1 y 10")
# Mensaje informativo para que el usuario sepa qué se espera de él.
nota = int(input("Introduce la nota (1 y 10): "))
# input() pide texto al usuario. int() lo convierte a número entero.
# Si el usuario escribe "7", sin int() tendríamos la cadena "7", no el número.
# PRUEBA: quita el int() y verás que la comparación nota < 1 da error.
while nota < 1 or nota > 10:
# Bucle de validación: se repite MIENTRAS la nota sea incorrecta.
# "or" significa que basta con que UNA de las dos condiciones sea True
# para que el bucle continúe.
# Ejemplos de notas incorrectas: 0, -5, 11, 100
# ALTERNATIVA equivalente: while not (1 <= nota <= 10):
print("Nota incorrecta, mendrugo")
# Mensaje de error. En un programa real usaríamos algo más amable,
# como: print("Nota incorrecta. Debe estar entre 1 y 10.")
nota = int(input("Introduce la nota (1 y 10): "))
# Volvemos a pedir la nota para que el usuario pueda corregirla.
# Esto SOBREESCRIBE el valor anterior de "nota".
# En la siguiente vuelta del while, se comprobará este nuevo valor.
return nota
# "return" devuelve el valor de "nota" al lugar donde se llamó la función.
# Solo llegamos aquí cuando la nota ES válida (el while ha terminado).
# Sin "return", la función haría todo el proceso pero no nos daría el resultado.
# Sería como una máquina expendedora que acepta el dinero pero no da el producto.
# =============================================================================
# CASOS DE USO: TRES FORMAS DE USAR LA FUNCIÓN
# =============================================================================
# Una función puede usarse de varias maneras según lo que necesitemos hacer
# con el valor que devuelve. Aquí vemos las tres más habituales.
# =============================================================================
# --- CASO 1: Imprimir el resultado directamente ---
print(pedir_nota())
# Python ejecuta pedir_nota(), obtiene la nota válida y la pasa a print().
# El valor devuelto por la función se usa al momento y no se guarda en ningún sitio.
# Útil cuando solo queremos mostrar el resultado una vez.
# --- CASO 2: Guardar el resultado en una variable ---
nota_alumno = pedir_nota()
# El valor que devuelve pedir_nota() se guarda en la variable "nota_alumno".
# A partir de aquí podemos usar "nota_alumno" tantas veces como queramos.
# VENTAJA respecto al caso 1: podemos usar el valor varias veces sin pedir
# la nota de nuevo. Por ejemplo: print(nota_alumno), calcular media, etc.
# --- CASO 3: Añadir el resultado a una lista ---
lista_notas = []
# Creamos una lista vacía con []. Aquí iremos acumulando notas.
lista_notas.append(nota_alumno)
# .append() añade un elemento AL FINAL de la lista.
# Aquí añadimos la nota que ya teníamos guardada en la variable del caso 2.
# lista_notas pasa de [] a [nota_alumno], por ejemplo: [7]
lista_notas.append(pedir_nota())
# Llamamos a pedir_nota() y el valor que devuelve se añade directamente a la lista.
# Es lo mismo que hacer:
# nueva_nota = pedir_nota()
# lista_notas.append(nueva_nota)
# pero en una sola línea.
print(lista_notas)
# Imprime la lista completa con los dos valores acumulados.
# Ejemplo de salida: [7, 9]
# =============================================================================
# EJEMPLO REAL: RECOGER LAS NOTAS DE UN GRUPO DE ALUMNOS
# =============================================================================
# Ahora combinamos todo lo anterior con un bucle for para recorrer
# una lista de nombres y pedir la nota de cada alumno.
# Este es el patrón más habitual en programas reales.
# =============================================================================
alumnos = ["Monica", "Ermengol", "Jordi", "Marisol"]
# Lista con los nombres de los alumnos del grupo.
# ALTERNATIVA: pedir los nombres por teclado con un bucle while.
notas = []
# Lista vacía donde iremos guardando las notas según las vayamos pidiendo.
# Es importante crearla ANTES del bucle para no borrarla en cada vuelta.
for alumno in alumnos:
# El bucle recorre la lista "alumnos" de principio a fin.
# En cada vuelta, "alumno" toma el valor del siguiente nombre:
# Vuelta 1: alumno = "Monica"
# Vuelta 2: alumno = "Ermengol"
# Vuelta 3: alumno = "Jordi"
# Vuelta 4: alumno = "Marisol"
print("Dime la nota del alumno", alumno)
# Informamos de qué alumno estamos introduciendo.
# Ejemplo de salida: "Dime la nota del alumno Monica"
# ALTERNATIVA con f-string: print(f"Dime la nota de {alumno}")
notas.append(pedir_nota())
# Llamamos a pedir_nota() para obtener una nota válida
# y la añadimos al final de la lista "notas".
# Al terminar el bucle, "notas" tendrá una nota por cada alumno.
# Ejemplo: [8, 6, 9, 7]
# Al salir del bucle tenemos dos listas relacionadas:
# alumnos = ["Monica", "Ermengol", "Jordi", "Marisol"]
# notas = [8, 6, 9, 7 ]
# El alumno de la posición 0 tiene la nota de la posición 0, etc.
#
# RETO 1: imprime cada alumno con su nota usando un bucle for y range().
# RETO 2: calcula la nota media del grupo con sum(notas) / len(notas).
# RETO 3: encuentra al alumno con la nota más alta.