Crear funciones para reutilizar soluciones

Ciencia y tecnologíaCrear funciones para reutilizar soluciones

Cuando una operación aparece en varios lugares conviene darle un nombre y definirla una sola vez. Las funciones permiten dividir un programa en piezas que reciben datos y producen resultados. En esta lección aprenderás a distinguir parámetros, argumentos y valores devueltos. También evitarás un error muy común: confundir mostrar un resultado con entregarlo a otra parte del programa.

Definir una operación con nombre

La palabra def introduce una función. Después escribes su nombre, los parámetros entre paréntesis y dos puntos. El bloque sangrado contiene las instrucciones que se ejecutarán cuando llames a esa función. Definirla no equivale a ejecutarla inmediatamente.

def calcular_doble(numero):
    return numero * 2

resultado = calcular_doble(4)
print(resultado)

numero es el parámetro: el nombre que utiliza la función internamente. Cuatro es el argumento proporcionado en la llamada. return entrega el resultado y termina esa ejecución de la función. La variable resultado recibe ocho. Puedes volver a llamar a la misma función con otro argumento sin modificar su definición.

Elige nombres que expresen acciones. calcular_cajas, limpiar_titulo o contar_pendientes explican mejor la intención que proceso o funcion1. No necesitas una función para cada línea pero sí resulta útil separar operaciones que tienen una responsabilidad reconocible y que puedes comprobar por su cuenta.

Escribir un contrato sencillo

Antes de programar una función anota qué recibe, qué devuelve y bajo qué condiciones debe utilizarse. Ese pequeño contrato evita mezclar decisiones incompatibles. Para calcular cajas podríamos exigir una cantidad entera no negativa y una capacidad entera positiva. El resultado será un número entero de cajas.

def calcular_cajas(objetos, capacidad):
    return (objetos + capacidad - 1) // capacidad

print(calcular_cajas(23, 5))
print(calcular_cajas(20, 5))
print(calcular_cajas(0, 5))

Los resultados esperados son cinco, cuatro y cero. Esta versión supone que los argumentos ya son válidos. No oculta esa limitación. En otra función o en la parte que recoge los datos deberás comprobarla. Más adelante podrás incorporar rechazos explícitos si necesitas que la propia función defienda su contrato.

Los argumentos posicionales se relacionan con los parámetros por su orden. Intercambiar objetos y capacidad cambia el cálculo. También puedes escribir calcular_cajas(objetos=23, capacidad=5) para hacer explícito el significado. No mezcles ambos estilos sin necesidad en ejemplos que todavía estás aprendiendo a leer.

print y return no son equivalentes

print muestra información. return entrega un valor a quien ha llamado a la función. Puedes mostrar algo sin devolverlo y devolver algo sin mostrarlo. Una función que termina sin ejecutar un return con valor devuelve None.

def mostrar_doble(numero):
    print(numero * 2)

resultado = mostrar_doble(4)
print(resultado)

Este programa muestra ocho desde el interior de la función y después None al imprimir resultado. No es que se haya perdido el ocho. La función nunca lo devolvió. Si quieres utilizar el doble en otro cálculo emplea return. Si la responsabilidad consiste únicamente en mostrar un menú, utilizar print puede ser apropiado.

Separar cálculo y presentación facilita reutilizar una operación. calcular_doble sirve tanto para mostrar un mensaje como para sumar el resultado a otra cantidad. Una función que pide datos con input, calcula y muestra todo junto es más difícil de probar porque obliga a interactuar incluso cuando solo quieres comprobar la fórmula.

Variables locales y datos compartidos

Los nombres creados dentro de una función suelen pertenecer a su ámbito local. No puedes utilizarlos fuera como si existieran en todo el archivo. Es preferible pasar los datos necesarios mediante parámetros y obtener resultados mediante return en lugar de depender de variables globales dispersas.

Sin embargo, si pasas una lista la función recibe una referencia al mismo objeto. Puede modificarlo con append y ese cambio será visible fuera. Debes decidir y explicar si una función modifica sus argumentos o si calcula un resultado sin alterarlos. Ambos comportamientos pueden ser válidos cuando el contrato es claro.

def agregar_tarea(tareas, titulo):
    tareas.append({"titulo": titulo, "hecha": False})

agenda = []
agregar_tarea(agenda, "Practicar funciones")
print(len(agenda))

La longitud es uno porque agregar_tarea modifica la lista recibida. Este ejemplo aún no limpia ni valida el título. Lo mejoraremos en el proyecto. Por ahora sirve para reconocer el efecto sobre una estructura compartida y distinguirlo de devolver una lista completamente nueva.

Una función que cuenta sin modificar

Para contar tareas pendientes puedes recorrer los registros y aumentar un contador cuando hecha sea False. La función no necesita preguntar nada ni cambiar estados. Su resultado puede comprobarse con una lista inventada.

def contar_pendientes(tareas):
    cantidad = 0
    for tarea in tareas:
        if not tarea["hecha"]:
            cantidad += 1
    return cantidad

El return está fuera del bucle. Si lo colocaras dentro terminarías la función durante la primera vuelta y no contarías el resto. La sangría vuelve a expresar una decisión esencial. Prueba la función con lista vacía, con una pendiente y con dos registros de estados diferentes.

Errores habituales

  • Pensar que una función se ejecuta por el hecho de definirla.
  • Utilizar print cuando otra parte del programa necesita un valor devuelto.
  • Situar return dentro de un bucle que todavía debe continuar.
  • Modificar una lista recibida sin documentar ese efecto.
  • Depender de variables exteriores que no aparecen en los parámetros.

Lo que deberías recordar

  • Una función reúne una responsabilidad bajo un nombre.
  • Los parámetros reciben los argumentos de cada llamada.
  • return y print cumplen tareas diferentes.
  • El contrato debe explicar los datos válidos y los efectos sobre ellos.

Ejercicio práctico

En la undécima hoja escribe el contrato de calcular_cajas y comprueba sus tres llamadas. Después implementa contar_pendientes con una lista que contenga dos tareas pendientes y una terminada. Debe devolver dos sin modificar los registros.

Por último compara calcular_doble y mostrar_doble guardando el resultado de ambas llamadas. Anota qué aparece en pantalla y qué valor recibe cada variable. Explicar esa diferencia con tus propias palabras es el objetivo principal de la práctica. No avances solo porque los mensajes visibles se parezcan.

Siguiente capítulo: Leer errores y validar las entradas.

Volver al índice del curso de programación desde cero.

Últimos posts

Artículos más vistos

Horóscopo diario
Menú diario