Saltar al contenido principal

5.1 Funciones y parámetros

En Python, una función es un bloque de código que agrupa un conjunto de instrucciones para realizar una tarea concreta.
Su uso permite dividir un programa en partes más pequeñas y reutilizables, lo que mejora la organización, la legibilidad y el mantenimiento del código.

Las funciones pueden recibir datos de entrada, llamados parámetros, y devolver un resultado, utilizando la palabra clave return.
Este mecanismo es fundamental para construir programas modulares y evitar la repetición de código.


1️⃣ Definición y llamada de una función​

Las funciones se definen en Python mediante la palabra clave def, seguida del nombre de la función, los parámetros entre paréntesis y el bloque de instrucciones indentado.
Para ejecutar una función, se realiza una llamada indicando su nombre y los argumentos correspondientes.

Ejemplo básico de definición y llamada de función
def saludar(nombre):
"""Muestra un saludo por pantalla."""
print(f"Hola, {nombre}!")

saludar("Ana")
en este ejemplo
  • def indica el comienzo de la definición.
  • saludar es el nombre de la función.
  • nombre es el parámetro que recibe el valor al llamar a la función.
  • print() ejecuta la acción principal de la función.
  • La última línea realiza la llamada pasando el argumento "Ana".

🟩 Ventajas del uso de funciones​

Las funciones aportan varias ventajas importantes al escribir programas:

  • Reutilización del código: se puede invocar la misma función tantas veces como se necesite.
  • Claridad: cada función agrupa instrucciones que cumplen una única finalidad.
  • Mantenimiento sencillo: los cambios o correcciones se realizan en un único lugar.
  • Pruebas más simples: cada función puede probarse de forma independiente.
Ejemplo de reutilización de funciones
def area_rectangulo(base, altura):
return base * altura

print(area_rectangulo(4, 3)) # 12
print(area_rectangulo(10, 2)) # 20

🟦 Estructura general de una función​

La forma general de una función en Python es la siguiente:

✍️ Sintaxis general de una función
def nombre_funcion(parámetros):
"""Descripción opcional (docstring)."""
# Bloque de instrucciones
return valor_opcional
en este ejemplo
  • def introduce la definición.
  • El nombre debe seguir las reglas de los identificadores de Python.
  • Los parámetros son los datos de entrada.
  • El bloque indentado contiene las operaciones que realiza.
  • return devuelve el resultado (puede omitirse si no se necesita devolver nada). Si la función no incluye return, devuelve implícitamente None.

🟨 Retornar múltiples valores​

En Python, una función puede devolver más de un valor separándolos por comas. Internamente, Python agrupa estos valores en una tupla, que puede desempaquetarse fácilmente al recibirlos.

Ejemplo de retorno múltiple
def dividir_y_resto(a, b):
"""Devuelve el cociente y el resto de una división entera."""
cociente = a // b
resto = a % b
return cociente, resto

c, r = dividir_y_resto(17, 5)
print(f"Cociente: {c}, Resto: {r}")
en este ejemplo

La función devuelve dos resultados: el cociente y el resto de la división. Al llamar a la función, ambos valores se asignan simultáneamente a las variables c y r. Esto permite obtener varios resultados sin necesidad de definir funciones adicionales.


2️⃣ Parámetros y argumentos​

Los datos que recibe una función se denominan parámetros. Cuando se llama a la función, los valores reales que se envían se llaman argumentos.

Por ejemplo, en la función def sumar(a, b):, los nombres a y b son parámetros, mientras que en la llamada sumar(3, 4) los valores 3 y 4 son argumentos.

Python permite utilizar varios tipos de parámetros:

  • Posicionales: el orden importa.
  • Nombrados (keyword arguments): se indican explícitamente.
  • Con valores por defecto: tienen un valor predefinido.
  • De solo posición o solo palabra clave: restringen cómo se pueden pasar los argumentos.
  • Arbitrarios: permiten un número variable de argumentos (se verán en el punto 2).

🟩 Parámetros posicionales​

Los parámetros posicionales son aquellos cuyo valor depende del orden en el que se pasan los argumentos. Son los más comunes.

Ejemplo de parámetros posicionales
def distancia(x1, y1, x2, y2):
"""Calcula la distancia entre dos puntos."""
return ((x2 - x1)**2 + (y2 - y1)**2) ** 0.5

print(distancia(0, 0, 3, 4)) # 5.0
en este ejemplo

Los valores 0, 0, 3, 4 se asignan a x1, y1, x2, y2 en ese orden. Si se cambiara el orden, el resultado sería diferente.

🟦 keyword arguments​

Los argumentos con nombre permiten especificar de forma explícita qué valor corresponde a cada parámetro, sin importar el orden. El uso de argumentos con nombre mejora la legibilidad y evita errores, especialmente en funciones con muchos parámetros.

Ejemplo de argumentos con nombre
print(distancia(x1=0, y1=0, x2=3, y2=4))   # 5.0

🟨 Valores por defecto​

Un parámetro puede tener un valor por defecto, que se utiliza cuando no se especifica un argumento en la llamada.

Ejemplo de parámetro con valor por defecto
def potencia(base, exponente=2):
"""Calcula la potencia de un número."""
return base ** exponente

print(potencia(5)) # 25
print(potencia(2, 10)) # 1024
en este ejemplo

El segundo parámetro exponente tiene un valor predeterminado de 2. Por tanto, potencia(5) calcula el cuadrado y potencia(2,10) la potencia 2¹⁰.

Cuidado con los valores mutables por defecto

Cuando se usan listas, diccionarios u otros objetos mutables como valores por defecto, estos persisten entre llamadas y pueden generar resultados inesperados.

👎 Ejemplo de mal uso de valores mutables
def agregar(item, bolsa=[]):
bolsa.append(item)
return bolsa

print(agregar(1)) # [1]
print(agregar(2)) # [1, 2] ← comportamiento no deseado

El valor por defecto de bolsa se mantiene entre llamadas, porque se evalúa una única vez. Esto provoca que la lista se comparta entre ejecuciones de la función.

👍 Solución segura usando None
def agregar(item, bolsa=None):
if bolsa is None:
bolsa = []
bolsa.append(item)
return bolsa

Usar None evita que la lista se comparta entre ejecuciones, creando una nueva cada vez.

🟧 Límites en parámetros​

Python permite limitar cómo se pasan los argumentos usando los símbolos / y * en la definición.

def escalar(x, y, /, *, factor=1.0):
"""x e y son solo posicionales; factor solo por palabra clave."""
return (x * factor, y * factor)

print(escalar(3, 4, factor=2)) # (6, 8)
en este ejemplo
  • Los parámetros antes de / (en este caso x e y) deben pasarse solo por posición.
  • Los parámetros después de * (en este caso factor) deben pasarse solo con su nombre. Este mecanismo hace las funciones más claras y evita llamadas ambiguas.

3️⃣ Ámbito de las variables​

El ámbito o alcance determina en qué partes del programa es visible una variable. Python sigue la regla LEGB para buscar nombres: Local → Enclosing (envolvente) → Global → Built-in.

Ejemplo de ámbitos local y global
x = 10  # variable global

def f():
x = 20 # variable local
print("x dentro de f:", x)

def g():
global x
x = 30 # modifica la variable global
print("x dentro de g:", x)

f()
print("x global:", x)
g()
print("x global tras g:", x)
en este ejemplo

La función f() crea una variable local diferente de la global. En cambio, g() usa la palabra clave global para modificar la variable definida fuera.

🟩 Uso de nonlocal​

Cuando una función se define dentro de otra, puede ser necesario modificar una variable del ámbito envolvente (no global). Para ello se usa la palabra clave nonlocal.

Ejemplo de uso de nonlocal
def contador():
n = 0
def incrementar():
nonlocal n
n += 1
return n
return incrementar

c = contador()
print(c()) # 1
print(c()) # 2
en este ejemplo

nonlocal permite acceder y modificar una variable de una función envolvente. En este caso, la variable n conserva su valor entre llamadas a la función interna.


4️⃣ Docstrings e indicadores de tipos​

La documentación interna del código es fundamental para garantizar su comprensión, mantenimiento y reutilización. Python incorpora dos mecanismos complementarios para lograrlo: los docstrings y los indicadores de tipos. Ambos permiten que las funciones sean más claras, autoexplicativas y compatibles con herramientas de análisis estático.

🟩 Docstrings​

Un docstring (documentation string) es una cadena de texto especial que describe el propósito y funcionamiento de una función, clase o módulo. Se coloca inmediatamente después de la definición (def o class) y se encierra entre tres comillas dobles (""" ... """).

Ejemplo básico de Docstring
def saludar(nombre):
"""Muestra un saludo personalizado por pantalla."""
print(f"Hola, {nombre}!")
en este ejemplo

El texto entre triple comilla no se imprime, sino que actúa como documentación interna. Puede consultarse en cualquier momento usando help(saludar) o saludar.__doc__.

Estructura recomendada​

Para funciones más complejas se recomienda seguir el formato definido en la guía PEP 257:

  1. Una primera línea con una descripción breve y concisa.
  2. Una línea en blanco como separador.
  3. Información detallada sobre parámetros, valores devueltos y ejemplos.
Ejemplo de estructura recomendada
def potencia(base, exponente=2):
"""
Calcula la potencia de un número.

Parámetros:
base (float): número base.
exponente (int, opcional): potencia a la que se eleva la base (por defecto, 2).

Devuelve:
float: resultado de base elevado a exponente.
"""
return base ** exponente

Este formato permite que la documentación sea legible tanto para personas como para herramientas automáticas, como pydoc o los editores de código que muestran ayuda contextual.

🟦 Indicadores de tipo (type hints)​

Los indicadores de tipo especifican el tipo de datos que se espera en los parámetros y el tipo que la función devuelve. No modifican el comportamiento del programa, pero sirven como guía para el programador y facilitan el uso de analizadores estáticos (linters).

Ejemplo de type hints
def calcular_media(valores: list[float]) -> float:
"""
Calcula la media aritmética de una lista de números.

Parámetros:
valores (list[float]): lista de valores numéricos.

Devuelve:
float: valor medio de todos los números de la lista.
"""
if not valores:
raise ValueError("La lista no puede estar vacía.")
return sum(valores) / len(valores)
en este ejemplo
  • valores: list[float] indica que el parámetro debe ser una lista de números reales.
  • -> float especifica que la función devuelve un número de tipo real. Estas anotaciones mejoran la legibilidad y permiten detectar errores antes de ejecutar el código.

🟨 Relación entre docstrings y type hints​

Ambos elementos tienen funciones distintas pero complementarias:

ElementoFunción principalInterpretado por
DocstringExplica qué hace la función y cómo usarlaPersonas, help(), generadores de documentación
Indicadores de tipoIndican los tipos de datos esperados y devueltosEditores, linters y analizadores estáticos

Combinarlos ofrece una documentación completa tanto para el desarrollador como para las herramientas de análisis.

🟧 Ejemplo completo​

def filtrar_mayores(valores: list[int], umbral: int = 0) -> list[int]:
"""
Devuelve una lista con los números mayores que el umbral indicado.

Parámetros:
valores (list[int]): lista de números enteros.
umbral (int, opcional): valor límite. Por defecto es 0.

Devuelve:
list[int]: lista con los valores que superan el umbral.

Ejemplo:
>>> filtrar_mayores([3, -1, 5, 0, 8], umbral=2)
[3, 5, 8]
"""
return [v for v in valores if v > umbral]
en este ejemplo

La combinación de docstring y anotaciones de tipo proporciona una descripción completa del comportamiento de la función. Esto hace que el código sea más auto-documentado, legible y mantenible, cumpliendo con las buenas prácticas del desarrollo profesional en Python.


✅ Buenas prácticas​

buenas prácticas para la creación de funciones
  • Utilizar nombres de función claros y descriptivos.
  • Mantener las funciones breves y con un propósito definido.
  • Evitar el uso de global siempre que sea posible.
  • Documentar las funciones con docstrings.
  • Emplear anotaciones de tipo para mejorar la legibilidad del código.
Ejemplo con docstring y anotaciones de tipo
def media(valores: list[float]) -> float:
"""Calcula la media aritmética de una lista de números."""
return sum(valores) / len(valores)