Funciones básicas

Objetivos del módulo

Al completar este módulo serás capaz de:

  • Entender qué son las funciones y por qué usarlas
  • Crear funciones con def
  • Usar parámetros y argumentos
  • Devolver valores con return
  • Entender el scope de variables

¿Por qué necesitas funciones?

Imagina que eres chef en un restaurante. Cada vez que un cliente pide una tortilla, podrías explicar desde cero cómo batir huevos, qué sartén usar, cuánto aceite añadir… O podrías tener una receta que sigues siempre. La receta se escribe una vez y se usa mil veces.

Las funciones son las recetas de la programación. En lugar de repetir el mismo código una y otra vez, lo escribes una vez, le das un nombre, y lo usas cuando lo necesites.

Los problemas de no usar funciones

Mira este código sin funciones:

 1# Calcular el área de un rectángulo de 5x3
 2area1 = 5 * 3
 3print(f"Área: {area1}")
 4
 5# Calcular el área de otro rectángulo de 10x7
 6area2 = 10 * 7
 7print(f"Área: {area2}")
 8
 9# Y otro más de 8x4
10area3 = 8 * 4
11print(f"Área: {area3}")

¿Qué pasa si ahora quieres añadir el perímetro también? Tendrías que modificar tres lugares. ¿Y si tienes 50 rectángulos? Se convierte en una pesadilla.

El principio DRY: Don’t Repeat Yourself

En programación existe una regla de oro: no te repitas. Si copias y pegas código, algo está mal. Las funciones son la solución:

1def calcular_area(base, altura):
2    return base * altura
3
4# Ahora es fácil y limpio
5print(f"Área: {calcular_area(5, 3)}")
6print(f"Área: {calcular_area(10, 7)}")
7print(f"Área: {calcular_area(8, 4)}")
Beneficios de las funciones
  • Reutilización: Escribe una vez, usa muchas veces
  • Organización: Divide problemas grandes en piezas pequeñas
  • Legibilidad: calcular_precio() es más claro que 20 líneas de código
  • Mantenimiento: Si hay un bug, lo arreglas en un solo lugar

Tu primera función

Una función es como una caja mágica: le metes algo (entrada), hace su trabajo (procesamiento), y te devuelve algo (salida).

graph LR
    A["Entrada<br/>(parámetros)"] --> B["Función<br/>procesamiento"]
    B --> C["Salida<br/>(return)"]

Sintaxis básica

1def nombre_de_la_funcion(parametro1, parametro2):
2    # Cuerpo de la función (lo que hace)
3    resultado = parametro1 + parametro2
4    return resultado

Desglosemos cada parte:

Elemento Qué es Ejemplo
def Palabra clave que indica “voy a definir una función” def
Nombre Identificador de la función (en minúsculas, con guiones bajos) calcular_precio
Paréntesis Contienen los parámetros de entrada (precio, descuento)
Dos puntos Indican que empieza el cuerpo de la función :
Cuerpo Código indentado que se ejecuta al llamar la función return precio * 0.9
return Devuelve un valor (opcional) return resultado

Ejemplo paso a paso

 1# 1. DEFINIR la función (escribir la receta)
 2def saludar(nombre):
 3    mensaje = f"¡Hola, {nombre}!"
 4    return mensaje
 5
 6# 2. LLAMAR a la función (usar la receta)
 7resultado = saludar("Ana")
 8print(resultado)  # ¡Hola, Ana!
 9
10# Puedes llamarla las veces que quieras
11print(saludar("Luis"))   # ¡Hola, Luis!
12print(saludar("María"))  # ¡Hola, María!
Definir vs Llamar

Definir una función (con def) es como escribir una receta. No cocina nada, solo guarda las instrucciones.

Llamar a una función (escribiendo su nombre con paréntesis) es cocinar siguiendo la receta. Ahí es cuando realmente se ejecuta el código.


Parámetros y argumentos

Imagina un formulario de registro. El formulario tiene campos vacíos (nombre, email, teléfono). Cuando alguien lo rellena, esos campos tienen valores concretos.

  • Los parámetros son los campos vacíos del formulario (la definición)
  • Los argumentos son los valores concretos que rellenas (la llamada)
1#          parámetros ↓
2def registrar(nombre, email):
3    print(f"Usuario: {nombre}, Email: {email}")
4
5#             argumentos ↓
6registrar("Ana García", "[email protected]")

Parámetros posicionales

El orden importa. El primer argumento va al primer parámetro, el segundo al segundo…

1def presentar(nombre, edad, ciudad):
2    print(f"Soy {nombre}, tengo {edad} años y vivo en {ciudad}")
3
4presentar("Ana", 25, "Madrid")      # Correcto
5presentar(25, "Ana", "Madrid")      # ¡Error! 25 no es un nombre

Parámetros con nombre (keyword arguments)

Puedes especificar el nombre del parámetro al llamar. Así el orden no importa:

1presentar(ciudad="Barcelona", nombre="Luis", edad=30)
2# Soy Luis, tengo 30 años y vivo en Barcelona

Parámetros con valores por defecto

A veces quieres que un parámetro tenga un valor “de fábrica” si no se especifica:

1def saludar(nombre, saludo="Hola"):
2    return f"{saludo}, {nombre}!"
3
4print(saludar("Ana"))              # Hola, Ana!
5print(saludar("Ana", "Buenos días"))  # Buenos días, Ana!
Regla importante

Los parámetros con valor por defecto deben ir después de los que no tienen. Si no, Python se confunde:

1# Mal
2def funcion(a=1, b):  # SyntaxError!
3
4# Bien
5def funcion(b, a=1):  # Correcto

Número variable de argumentos

A veces no sabes cuántos argumentos recibirás. Python tiene dos herramientas para esto:

 1# *args: recibe múltiples argumentos posicionales como tupla
 2def sumar_todos(*numeros):
 3    return sum(numeros)
 4
 5print(sumar_todos(1, 2))           # 3
 6print(sumar_todos(1, 2, 3, 4, 5))  # 15
 7
 8# **kwargs: recibe argumentos con nombre como diccionario
 9def crear_perfil(**datos):
10    for clave, valor in datos.items():
11        print(f"{clave}: {valor}")
12
13crear_perfil(nombre="Ana", edad=25, ciudad="Madrid")
14# nombre: Ana
15# edad: 25
16# ciudad: Madrid

Devolver valores con return

La palabra return hace dos cosas:

  1. Devuelve un valor al código que llamó la función
  2. Termina la ejecución de la función inmediatamente

La diferencia entre print() y return

Esta es una confusión muy común entre principiantes. Piensa en un trabajador:

  • print() es como un trabajador que hace su trabajo y te cuenta lo que hizo (muestra en pantalla)
  • return es como un trabajador que hace su trabajo y te entrega el resultado (puedes usarlo después)
 1# Solo muestra en pantalla, no devuelve nada útil
 2def sumar_print(a, b):
 3    print(a + b)
 4
 5# Devuelve el valor, puedes usarlo después
 6def sumar_return(a, b):
 7    return a + b
 8
 9# Con print: no puedes hacer nada con el resultado
10resultado1 = sumar_print(2, 3)  # Muestra: 5
11print(resultado1)               # None (no devolvió nada)
12
13# Con return: el resultado es útil
14resultado2 = sumar_return(2, 3)
15print(resultado2)               # 5
16print(resultado2 * 2)           # 10 (puedes operarlo)

Retornar múltiples valores

Python permite devolver varios valores a la vez (en realidad, devuelve una tupla):

 1def analizar_numeros(lista):
 2    minimo = min(lista)
 3    maximo = max(lista)
 4    promedio = sum(lista) / len(lista)
 5    return minimo, maximo, promedio
 6
 7# Desempaquetar los valores
 8menor, mayor, media = analizar_numeros([1, 5, 3, 9, 2])
 9print(f"Mínimo: {menor}, Máximo: {mayor}, Promedio: {media}")
10# Mínimo: 1, Máximo: 9, Promedio: 4.0

Funciones sin return

Si una función no tiene return, devuelve None automáticamente:

1def saludar(nombre):
2    print(f"Hola, {nombre}")
3    # No hay return
4
5resultado = saludar("Ana")  # Muestra: Hola, Ana
6print(resultado)            # None

return termina la función

Cuando Python encuentra un return, la función termina inmediatamente:

 1def verificar_edad(edad):
 2    if edad < 0:
 3        return "Edad inválida"  # Si es negativa, termina aquí
 4    if edad < 18:
 5        return "Menor de edad"  # Si es menor, termina aquí
 6    return "Mayor de edad"      # Si llegamos aquí, es adulto
 7
 8print(verificar_edad(-5))   # Edad inválida
 9print(verificar_edad(15))   # Menor de edad
10print(verificar_edad(25))   # Mayor de edad

Scope: ¿Dónde viven las variables?

Imagina una casa con habitaciones. Lo que pasa en la cocina, se queda en la cocina. Si dejas una sartén en la cocina, no aparece mágicamente en el dormitorio.

En programación, las variables también tienen su “habitación”: es lo que llamamos scope (ámbito).

graph TB
    subgraph Global["Ámbito Global (toda la casa)"]
        A["variable_global = 'visible en toda la casa'"]
        subgraph Funcion["Ámbito Local (una habitación)"]
            B["variable_local = 'solo visible aquí dentro'"]
        end
    end

Variables locales

Las variables creadas dentro de una función son locales. Solo existen mientras la función se ejecuta:

1def mi_funcion():
2    mensaje = "Soy local"  # Variable local
3    print(mensaje)
4
5mi_funcion()      # Soy local
6print(mensaje)    # NameError: 'mensaje' is not defined

Variables globales

Las variables creadas fuera de las funciones son globales. Son visibles desde cualquier parte:

1saludo = "Hola"  # Variable global
2
3def saludar():
4    print(saludo)  # Puede LEER la variable global
5
6saludar()  # Hola

Modificar variables globales (y por qué evitarlo)

Si intentas modificar una variable global dentro de una función, Python crea una nueva variable local:

1contador = 0
2
3def incrementar():
4    contador = contador + 1  # ¡Error! Python piensa que es local
5    print(contador)
6
7incrementar()  # UnboundLocalError

Puedes usar global para forzar el acceso, pero no es recomendable:

1contador = 0
2
3def incrementar():
4    global contador  # "Usa la variable global, no crees una local"
5    contador = contador + 1
6
7incrementar()
8print(contador)  # 1
Evita variables globales

Las variables globales hacen el código difícil de entender y depurar. Si una función necesita un valor, pásalo como parámetro. Si necesita devolver algo, usa return.

1# Mal: usa variable global
2total = 0
3def sumar(x):
4    global total
5    total += x
6
7# Bien: usa parámetros y return
8def sumar(total, x):
9    return total + x

Documentar funciones (docstrings)

Un docstring es un texto que explica qué hace una función. Va justo después de la línea def, entre triple comillas:

 1def calcular_imc(peso, altura):
 2    """
 3    Calcula el Índice de Masa Corporal (IMC).
 4
 5    Args:
 6        peso: Peso en kilogramos
 7        altura: Altura en metros
 8
 9    Returns:
10        El IMC como número decimal
11    """
12    return peso / (altura ** 2)

¿Por qué documentar?

  • Para otros: Quien lea tu código (incluido tu yo del futuro) entenderá qué hace cada función
  • Para herramientas: IDEs y editores muestran el docstring cuando pasas el cursor sobre una función
  • Para generar documentación: Herramientas como Sphinx generan documentación automática
1# Ver el docstring de una función
2print(calcular_imc.__doc__)
3
4# O usando help()
5help(calcular_imc)

Buenas prácticas

Nombra funciones con verbos

El nombre debe describir qué hace la función:

 1# Mal: sustantivos o nombres confusos
 2def datos_usuario():
 3    pass
 4
 5def proceso():
 6    pass
 7
 8# Bien: verbos que indican acción
 9def obtener_datos_usuario():
10    pass
11
12def procesar_pedido():
13    pass
14
15def calcular_total():
16    pass
17
18def validar_email():
19    pass

Una función = una tarea

Cada función debe hacer una sola cosa bien. Si hace muchas cosas, divídela:

 1# Mal: hace demasiadas cosas
 2def procesar_usuario(datos):
 3    # Valida datos
 4    # Guarda en base de datos
 5    # Envía email de bienvenida
 6    # Genera estadísticas
 7    pass
 8
 9# Bien: funciones pequeñas y enfocadas
10def validar_datos(datos):
11    pass
12
13def guardar_usuario(datos):
14    pass
15
16def enviar_email_bienvenida(email):
17    pass

Mantén las funciones cortas

Si una función tiene más de 20-30 líneas, probablemente hace demasiado. Considera dividirla.

Cuándo crear una función

Crea una función cuando:

  • Repites código más de dos veces
  • Un bloque de código hace una tarea específica que puedes nombrar
  • Quieres simplificar código complejo dividiéndolo en partes
  • Necesitas testear una parte del código de forma aislada

Resumen

Concepto Descripción Ejemplo
def Define una función def mi_funcion():
Parámetros Variables de entrada (en la definición) def suma(a, b):
Argumentos Valores concretos (en la llamada) suma(2, 3)
return Devuelve un valor y termina la función return resultado
Valor por defecto Parámetro con valor “de fábrica” def f(x=10):
*args Múltiples argumentos posicionales def f(*args):
**kwargs Múltiples argumentos con nombre def f(**kwargs):
Scope local Variables dentro de la función Solo visibles en la función
Scope global Variables fuera de funciones Visibles en todo el programa
Docstring Documentación de la función “““Texto…”””

Ejercicios prácticos

Ejercicio 1: Calculadora de propinas

Crea una función calcular_propina(total, porcentaje=15) que calcule la propina de una cuenta. El porcentaje por defecto es 15%.

 1def calcular_propina(total, porcentaje=15):
 2    """
 3    Calcula la propina para una cuenta.
 4
 5    Args:
 6        total: El total de la cuenta
 7        porcentaje: El porcentaje de propina (por defecto 15%)
 8
 9    Returns:
10        La cantidad de propina a dejar
11    """
12    propina = total * (porcentaje / 100)
13    return propina
14
15# Pruebas
16print(calcular_propina(100))      # 15.0 (15% por defecto)
17print(calcular_propina(100, 20))  # 20.0 (20%)
18print(calcular_propina(50, 10))   # 5.0 (10%)
Ejercicio 2: Validador de contraseñas

Crea una función validar_password(password) que verifique si una contraseña cumple:

  • Al menos 8 caracteres
  • Al menos una mayúscula
  • Al menos un número

Devuelve True si cumple todo, False si no.

 1def validar_password(password):
 2    """
 3    Valida si una contraseña cumple los requisitos de seguridad.
 4
 5    Args:
 6        password: La contraseña a validar
 7
 8    Returns:
 9        True si es válida, False si no
10    """
11    # Al menos 8 caracteres
12    if len(password) < 8:
13        return False
14
15    # Al menos una mayúscula
16    tiene_mayuscula = any(c.isupper() for c in password)
17    if not tiene_mayuscula:
18        return False
19
20    # Al menos un número
21    tiene_numero = any(c.isdigit() for c in password)
22    if not tiene_numero:
23        return False
24
25    return True
26
27# Pruebas
28print(validar_password("abc"))           # False (muy corta)
29print(validar_password("abcdefgh"))      # False (sin mayúscula ni número)
30print(validar_password("Abcdefgh"))      # False (sin número)
31print(validar_password("Abcdefg1"))      # True
Ejercicio 3: Estadísticas de una lista

Crea una función estadisticas(numeros) que reciba una lista de números y devuelva un diccionario con: mínimo, máximo, suma, promedio y cantidad de elementos.

 1def estadisticas(numeros):
 2    """
 3    Calcula estadísticas básicas de una lista de números.
 4
 5    Args:
 6        numeros: Lista de números
 7
 8    Returns:
 9        Diccionario con mínimo, máximo, suma, promedio y cantidad
10    """
11    if not numeros:
12        return None
13
14    return {
15        "minimo": min(numeros),
16        "maximo": max(numeros),
17        "suma": sum(numeros),
18        "promedio": sum(numeros) / len(numeros),
19        "cantidad": len(numeros)
20    }
21
22# Prueba
23datos = [10, 20, 30, 40, 50]
24resultado = estadisticas(datos)
25print(resultado)
26# {'minimo': 10, 'maximo': 50, 'suma': 150, 'promedio': 30.0, 'cantidad': 5}

Quiz

🎮 Quiz: Funciones básicas

0 / 0
Cargando preguntas...

Anterior: Ficheros Siguiente: Funciones avanzadas