Funciones en Python — ejercicios para afianzar lo que sabes
Las funciones en Python ejercicios con solución son el cierre perfecto de este tema. Ya viste la teoría y practicaste con programas reales. Ahora toca resolver por tu cuenta. Cuatro ejercicios en tres niveles con especial atención al error más silencioso de todos: olvidar el return y trabajar sin darte cuenta con None.
Como siempre: intenta resolverlo, usa la pista si llevas más de 10 minutos atascado, compara con la solución comentada al final y usa pythontutor.com
Tabla de Contenidos
Funciones en Python ejercicios — Nivel Básico
Ejercicio 1 — Conversor de notas entre sistemas
Escribe un conjunto de funciones que conviertan notas entre tres sistemas diferentes: el sistema español (0-10), el sistema americano (0-100) y el sistema de letras americano (A, B, C, D, F).
Las conversiones son:
- Española → Americana: multiplica por 10
- Americana → Española: divide entre 10
- Española → Letra: 9-10=A, 7-8=B, 5-6=C, 3-4=D, 0-2=F
- Letra → Española: A=9.5, B=7.5, C=5.5, D=3.5, F=1.5
La salida debe ser:
=== CONVERSOR DE NOTAS === Nota española (0-10): 7.5 --- Conversiones --- Sistema español: 7.5 Sistema americano: 75.0 Sistema de letras: B
💡 Pista — el error del return: Cada función debe devolver el valor con return, no imprimirlo con print. Si usas print dentro de la función y luego intentas hacer nota_americana = española_a_americana(7.5), la variable valdrá None aunque veas el número en pantalla. La función imprime pero no devuelve nada. Siempre return.
Ejercicio 2 — Generador de informe de notas
Usando las funciones del ejercicio anterior, escribe un programa que pida las notas de 4 asignaturas y genere un informe completo con la media, la nota más alta, la más baja y la conversión de cada nota a los tres sistemas.
=== INFORME DE NOTAS === Asignatura 1: FP1 Nota (0-10): 8.5 Asignatura 2: Estadística Nota (0-10): 7.0 Asignatura 3: Matemáticas Nota (0-10): 6.5 Asignatura 4: Bases de datos Nota (0-10): 9.0 --- Informe completo --- FP1: 8.5 | 85.0 | A Estadística: 7.0 | 70.0 | B Matemáticas: 6.5 | 65.0 | C Bases de datos: 9.0 | 90.0 | A Media: 7.75 → B Más alta: 9.0 (Bases de datos) Más baja: 6.5 (Matemáticas)
💡 Pista: Reutiliza las funciones del ejercicio anterior, eso es exactamente para lo que sirven. Crea una función pedir_asignatura() que pida nombre y nota y devuelva ambos. Crea otra función generar_informe(asignaturas) que reciba la lista y genere el resumen. El error del return aquí aparece si pedir_asignatura() hace print en vez de return, luego no puedes guardar los datos.
Funciones en Python ejercicios — Nivel Intermedio
Ejercicio 3 — Mini banco con funciones
Simula un sistema bancario básico con funciones para cada operación. El banco debe permitir consultar saldo, depositar dinero, retirar dinero y ver el historial de movimientos.
=== BANCO SERGIO LEARNS === Saldo inicial: 1000.0 € 1. Consultar saldo 2. Depositar 3. Retirar 4. Ver historial 0. Salir Opción: 2 Cantidad a depositar: 500 ✓ Depósito realizado: +500.0 € Saldo actual: 1500.0 € Opción: 3 Cantidad a retirar: 200 ✓ Retirada realizada: -200.0 € Saldo actual: 1300.0 € Opción: 4 --- Historial de movimientos --- Saldo inicial: +1000.0 € Depósito: +500.0 € Retirada: -200.0 € ───────────────────────────── Saldo actual: 1300.0 €
💡 Pistas:
- Crea estas funciones:
consultar_saldo(saldo),depositar(saldo, cantidad),retirar(saldo, cantidad),mostrar_historial(historial),menu_banco() - Las funciones
depositaryretirardeben devolver el nuevo saldo, ese es elreturnclave. Si olvidas elreturnel saldo nunca se actualiza aunque la función parezca funcionar - Guarda el historial como una lista de strings que vas actualizando con cada operación
retirardebe comprobar que hay saldo suficiente antes de retirar
Funciones en Python ejercicios — Desafío Final
Ejercicio 4 — Juego de dados con estadísticas
Simula un juego de dados donde el jugador lanza dos dados un número determinado de veces. El programa debe mostrar cada lanzamiento y al final generar estadísticas completas.
=== JUEGO DE DADOS === ¿Cuántos lanzamientos? 5 Lanzamiento 1: 🎲 3 + 🎲 5 = 8 Lanzamiento 2: 🎲 6 + 🎲 6 = 12 ← ¡Doble! Lanzamiento 3: 🎲 2 + 🎲 4 = 6 Lanzamiento 4: 🎲 1 + 🎲 1 = 2 ← ¡Doble! Lanzamiento 5: 🎲 4 + 🎲 3 = 7 --- Estadísticas --- Total lanzamientos: 5 Suma total: 35 Media por lanzamiento: 7.0 Máximo obtenido: 12 (lanzamiento 2) Mínimo obtenido: 2 (lanzamiento 4) Dobles conseguidos: 2 (40.0%) Distribución de resultados: 2: ██ (1 vez) 6: ██ (1 vez) 7: ██ (1 vez) 8: ██ (1 vez) 12: ██ (1 vez)
💡 Pistas:
- Crea estas funciones:
lanzar_dado(),lanzar_dos_dados(),es_doble(dado1, dado2),calcular_estadisticas(resultados),mostrar_distribucion(resultados),jugar() lanzar_dado()debe devolver el valor — si usaprinten vez dereturnno podrás sumar los dadoslanzar_dos_dados()debe devolver una tupla(dado1, dado2)— así puedes desempaquetar cond1, d2 = lanzar_dos_dados()- Para la distribución usa un diccionario donde la clave es el resultado y el valor es cuántas veces apareció
- Los bloques de la distribución se hacen con
"█" * cantidad
Soluciones Comentadas
Solución Ejercicio 1:
# Conversor de notas entre sistemas
def española_a_americana(nota):
return round(nota * 10, 1)
def americana_a_española(nota):
return round(nota / 10, 1)
def española_a_letra(nota):
if nota >= 9:
return "A"
elif nota >= 7:
return "B"
elif nota >= 5:
return "C"
elif nota >= 3:
return "D"
else:
return "F"
def letra_a_española(letra):
equivalencias = {"A": 9.5, "B": 7.5, "C": 5.5, "D": 3.5, "F": 1.5}
return equivalencias.get(letra.upper(), None)
def mostrar_conversiones(nota_española):
americana = española_a_americana(nota_española)
letra = española_a_letra(nota_española)
print(f"\n--- Conversiones ---")
print(f"Sistema español: {nota_española}")
print(f"Sistema americano: {americana}")
print(f"Sistema de letras: {letra}")
print("=== CONVERSOR DE NOTAS ===")
nota = float(input("Nota española (0-10): "))
if nota < 0 or nota > 10:
print("Error: la nota debe estar entre 0 y 10")
else:
mostrar_conversiones(nota)
Solución Ejercicio 2:
# Informe de notas — reutiliza funciones del ejercicio 1
def pedir_asignatura(numero):
nombre = input(f"Asignatura {numero}: ")
nota = float(input(f"Nota (0-10): "))
while nota < 0 or nota > 10:
print("Error: entre 0 y 10")
nota = float(input(f"Nota (0-10): "))
return nombre, nota
def generar_informe(asignaturas):
print("\n--- Informe completo ---")
notas = []
for nombre, nota in asignaturas:
americana = española_a_americana(nota)
letra = española_a_letra(nota)
print(f"{nombre:<20} {nota} | {americana} | {letra}")
notas.append(nota)
media = round(sum(notas) / len(notas), 2)
nota_max = max(notas)
nota_min = min(notas)
nombre_max = asignaturas[notas.index(nota_max)][0]
nombre_min = asignaturas[notas.index(nota_min)][0]
print(f"\nMedia: {media} → {española_a_letra(media)}")
print(f"Más alta: {nota_max} ({nombre_max})")
print(f"Más baja: {nota_min} ({nombre_min})")
print("=== INFORME DE NOTAS ===\n")
asignaturas = []
for i in range(1, 5):
nombre, nota = pedir_asignatura(i)
asignaturas.append((nombre, nota))
print()
generar_informe(asignaturas)
Solución Ejercicio 3:
# Mini banco con funciones
def consultar_saldo(saldo):
print(f"\nSaldo actual: {saldo} €")
def depositar(saldo, cantidad):
if cantidad <= 0:
print("Error: la cantidad debe ser positiva")
return saldo # devuelve el saldo sin cambios
nuevo_saldo = round(saldo + cantidad, 2)
print(f"✓ Depósito realizado: +{cantidad} €")
print(f"Saldo actual: {nuevo_saldo} €")
return nuevo_saldo # RETURN clave — devuelve el nuevo saldo
def retirar(saldo, cantidad):
if cantidad <= 0:
print("Error: la cantidad debe ser positiva")
return saldo
if cantidad > saldo:
print(f"Error: saldo insuficiente. Tienes {saldo} €")
return saldo
nuevo_saldo = round(saldo - cantidad, 2)
print(f"✓ Retirada realizada: -{cantidad} €")
print(f"Saldo actual: {nuevo_saldo} €")
return nuevo_saldo
def mostrar_historial(historial, saldo):
print("\n--- Historial de movimientos ---")
for movimiento in historial:
print(movimiento)
print("─" * 33)
print(f"Saldo actual: {saldo} €")
def menu_banco():
print("=== BANCO SERGIO LEARNS ===\n")
saldo_inicial = float(input("Saldo inicial: "))
saldo = saldo_inicial
historial = [f"Saldo inicial: +{saldo_inicial} €"]
while True:
print("\n1. Consultar saldo")
print("2. Depositar")
print("3. Retirar")
print("4. Ver historial")
print("0. Salir")
opcion = input("\nOpción: ")
if opcion == "0":
print("Hasta pronto")
break
elif opcion == "1":
consultar_saldo(saldo)
elif opcion == "2":
cantidad = float(input("Cantidad a depositar: "))
saldo_anterior = saldo
saldo = depositar(saldo, cantidad)
if saldo != saldo_anterior:
historial.append(f"Depósito: +{cantidad} €")
elif opcion == "3":
cantidad = float(input("Cantidad a retirar: "))
saldo_anterior = saldo
saldo = retirar(saldo, cantidad)
if saldo != saldo_anterior:
historial.append(f"Retirada: -{cantidad} €")
elif opcion == "4":
mostrar_historial(historial, saldo)
else:
print("Opción no válida")
menu_banco()
Solución Ejercicio 4:
# Juego de dados con estadísticas
import random
def lanzar_dado():
return random.randint(1, 6) # RETURN — devuelve el valor
def lanzar_dos_dados():
return lanzar_dado(), lanzar_dado() # devuelve tupla
def es_doble(dado1, dado2):
return dado1 == dado2
def calcular_estadisticas(resultados):
sumas = [d1 + d2 for d1, d2 in resultados]
dobles = sum(1 for d1, d2 in resultados if es_doble(d1, d2))
return {
"total": len(resultados),
"suma_total": sum(sumas),
"media": round(sum(sumas) / len(sumas), 2),
"maximo": max(sumas),
"lanz_max": sumas.index(max(sumas)) + 1,
"minimo": min(sumas),
"lanz_min": sumas.index(min(sumas)) + 1,
"dobles": dobles,
"pct_dobles": round(dobles / len(resultados) * 100, 1),
"sumas": sumas
}
def mostrar_distribucion(sumas):
print("Distribución de resultados:")
conteo = {}
for s in sumas:
conteo[s] = conteo.get(s, 0) + 1
for valor in sorted(conteo.keys()):
barra = "█" * conteo[valor]
print(f" {valor:2d}: {barra} ({conteo[valor]} vez)")
def jugar():
print("=== JUEGO DE DADOS ===")
n = int(input("¿Cuántos lanzamientos? "))
resultados = []
print()
for i in range(1, n + 1):
d1, d2 = lanzar_dos_dados()
suma = d1 + d2
doble = " ← ¡Doble!" if es_doble(d1, d2) else ""
print(f"Lanzamiento {i}: 🎲 {d1} + 🎲 {d2} = {suma}{doble}")
resultados.append((d1, d2))
stats = calcular_estadisticas(resultados)
print(f"\n--- Estadísticas ---")
print(f"Total lanzamientos: {stats['total']}")
print(f"Suma total: {stats['suma_total']}")
print(f"Media por lanzamiento: {stats['media']}")
print(f"Máximo obtenido: {stats['maximo']} (lanzamiento {stats['lanz_max']})")
print(f"Mínimo obtenido: {stats['minimo']} (lanzamiento {stats['lanz_min']})")
print(f"Dobles conseguidos: {stats['dobles']} ({stats['pct_dobles']}%)")
mostrar_distribucion(stats['sumas'])
jugar()
💡 Nota: aquí usamos listas y diccionarios que veremos en profundidad en el próximos tema. Por ahora trátalo como una colección de valores.
Chuletario — Funciones en Python
# ============================================
# CHULETARIO — Funciones en Python
# Sergio Learns · sergiolearns.com
# ============================================
# DEFINIR UNA FUNCIÓN
def nombre_funcion(parametro1, parametro2):
# cuerpo
return resultado
# LLAMAR A UNA FUNCIÓN
resultado = nombre_funcion(argumento1, argumento2)
# PARÁMETRO vs ARGUMENTO
def saludar(nombre): # nombre = PARÁMETRO (en la definición)
return f"Hola, {nombre}"
saludar("Sergio") # "Sergio" = ARGUMENTO (en la llamada)
# PARÁMETROS CON VALOR POR DEFECTO
def saludar(nombre, saludo="Hola"):
return f"{saludo}, {nombre}"
saludar("Sergio") # → "Hola, Sergio"
saludar("Sergio", "Buenos días") # → "Buenos días, Sergio"
# RETURN — devuelve valor Y termina la función
def sumar(a, b):
return a + b # termina aquí
print("nunca") # código muerto — nunca se ejecuta
# SIN RETURN → devuelve None
def imprimir(x):
print(x) # imprime pero NO devuelve
resultado = imprimir(5)
print(resultado) # → None ← error silencioso típico
# REGLA: si necesitas usar el resultado → usa return
# si solo necesitas que haga algo → no hace falta
# DEVOLVER MÚLTIPLES VALORES (tupla)
def min_max(lista):
return min(lista), max(lista)
minimo, maximo = min_max([3, 1, 4, 1, 5])
# FUNCIONES QUE LLAMAN A OTRAS
def es_aprobado(nota):
return nota >= 5
def clasificar(nota):
if nota >= 9: return "Sobresaliente"
elif nota >= 7: return "Notable"
elif es_aprobado(nota): return "Aprobado" # llama a otra función
else: return "Suspenso"
# ALCANCE — local vs global
x = 10 # global
def mi_funcion():
y = 20 # local — solo existe aquí
print(x) # puede leer globales
print(y)
mi_funcion()
print(x) # → 10 ✓
print(y) # → NameError ✗ — y no existe fuera
# CONSTANTES GLOBALES — en mayúsculas
IVA = 0.21
MAX_INTENTOS = 3
# PATRÓN: separar cálculo de presentación
def calcular(datos): # solo calcula, usa return
return resultado
def mostrar(resultado): # solo muestra, usa print
print(resultado)
def main(): # coordina todo
datos = input("...")
resultado = calcular(datos)
mostrar(resultado)
# ERRORES TÍPICOS
# 1. Olvidar return → función devuelve None
# 2. print en vez de return → valor no se puede usar
# 3. Llamar función antes de definirla → NameError
# 4. Variable local usada fuera → NameError
# 5. Modificar global desde función → bug difícil de encontrar
# DRY: Don't Repeat Yourself
# Si copias y pegas código → conviértelo en función
Python functions — exercises to consolidate what you know
Python functions exercises with solutions close out this topic. You’ve seen the theory and practised with real programs. Now solve on your own. Four exercises across three levels, with special focus on the most silent mistake of all, forgetting return and working with None without realising it.
Basic Level
Exercise 1 — Grade converter between systems
Write functions to convert grades between three systems: Spanish (0-10), American (0-100) and letter grades (A, B, C, D, F).
Conversions:
- Spanish → American: multiply by 10
- American → Spanish: divide by 10
- Spanish → Letter: 9-10=A, 7-8=B, 5-6=C, 3-4=D, 0-2=F
- Letter → Spanish: A=9.5, B=7.5, C=5.5, D=3.5, F=1.5
💡 Hint — the return mistake: Every function must return the value, not print it. If you use print inside the function and then try american = spanish_to_american(7.5), the variable will be None even though you saw the number on screen. The function printed but returned nothing. Always return.
Exercise 2 — Grade report generator
Using the functions from exercise 1, ask for 4 subject grades and generate a complete report with average, highest, lowest and conversion of each grade to all three systems.
💡 Hint: Reuse the functions from exercise 1, that’s exactly what they’re for. The return mistake appears here if your ask_subject() function uses print instead of return, then you can’t store the data.
Intermediate Level
Exercise 3 — Mini bank with functions
Simulate a basic banking system with functions for each operation: check balance, deposit, withdraw and view transaction history.
💡 Hints:
- Create:
check_balance(balance),deposit(balance, amount),withdraw(balance, amount),show_history(history, balance),bank_menu() depositandwithdrawmust return the new balance, that’s the keyreturn. Forgetting it means the balance never updates even though the function seems to work- Store history as a list of strings updated with each operation
withdrawmust check for sufficient funds before withdrawing
Final Challenge
Exercise 4 — Dice game with statistics
Simulate a dice game where the player rolls two dice a set number of times. Show each roll and generate complete statistics at the end including doubles percentage and result distribution.
💡 Hints:
- Create:
roll_die(),roll_two_dice(),is_double(d1, d2),calculate_stats(results),show_distribution(sums),play() roll_die()must return the value, if it usesprintinstead you can’t add the diceroll_two_dice()should return a tuple(die1, die2), unpack withd1, d2 = roll_two_dice()- Use a dictionary for distribution: key = result, value = count
- Build bars with
"█" * count
(Solutions same as Spanish version above)
Cheat sheet — Python functions
# ============================================
# CHEAT SHEET — Python Functions
# Sergio Learns · sergiolearns.com
# ============================================
# DEFINE A FUNCTION
def function_name(param1, param2):
# body
return result
# CALL A FUNCTION
result = function_name(arg1, arg2)
# PARAMETER vs ARGUMENT
def greet(name): # name = PARAMETER (in definition)
return f"Hello, {name}"
greet("Sergio") # "Sergio" = ARGUMENT (in call)
# DEFAULT PARAMETER VALUES
def greet(name, greeting="Hello"):
return f"{greeting}, {name}"
# RETURN — returns value AND ends function
def add(a, b):
return a + b
print("never") # dead code — never executes
# WITHOUT RETURN → returns None
def display(x):
print(x) # prints but does NOT return
result = display(5)
print(result) # → None ← classic silent mistake
# RULE: need to use result elsewhere → use return
# just need it to do something → no need
# RETURN MULTIPLE VALUES
def min_max(lst):
return min(lst), max(lst)
minimum, maximum = min_max([3, 1, 4, 1, 5])
# FUNCTIONS CALLING EACH OTHER
def is_passing(grade):
return grade >= 5
def classify(grade):
if grade >= 9: return "Outstanding"
elif grade >= 7: return "Good"
elif is_passing(grade): return "Passed"
else: return "Failed"
# SCOPE — local vs global
x = 10 # global
def my_function():
y = 20 # local — only exists here
print(x) # can read globals
print(x) # → 10 ✓
print(y) # → NameError ✗
# GLOBAL CONSTANTS — in UPPERCASE
VAT = 0.21
MAX_ATTEMPTS = 3
# PATTERN: separate calculation from presentation
def calculate(data): return result # only calculates
def display(result): print(result) # only displays
def main(): # coordinates
data = input("...")
display(calculate(data))
# COMMON MISTAKES
# 1. Forgetting return → function returns None
# 2. print instead of return → value can't be used
# 3. Calling function before defining it → NameError
# 4. Local variable used outside → NameError
# DRY: Don't Repeat Yourself
# If you copy-paste code → turn it into a function