Python

Python

Tutorial Python: Funciones

Aprende las funciones en Python: definición, parámetros, return y docstrings para escribir código organizado y reutilizable.

Aprende Python y certifícate

Definición básica superficial

Las funciones en Python son bloques de código reutilizables que realizan una tarea específica. Puedes imaginarlas como pequeñas "recetas" que puedes llamar cuando necesites ejecutar esa tarea en particular, sin tener que escribir el mismo código una y otra vez.

Una función en Python se define utilizando la palabra clave def, seguida del nombre de la función y paréntesis. El código que forma parte de la función debe estar indentado (con 4 espacios, según la convención de Python).

def saludar():
    print("¡Hola, mundo!")

Para ejecutar o "llamar" a una función, simplemente escribes su nombre seguido de paréntesis:

saludar()  # Imprime: ¡Hola, mundo!

Las funciones son fundamentales en la programación porque nos permiten:

  • Organizar el código en bloques lógicos y manejables
  • Reutilizar código en diferentes partes de nuestro programa
  • Simplificar la lectura y mantenimiento del código

Veamos un ejemplo práctico de una función que calcula el área de un rectángulo:

def calcular_area_rectangulo(base, altura):
    area = base * altura
    return area

# Uso de la función
resultado = calcular_area_rectangulo(5, 3)
print(f"El área del rectángulo es: {resultado}")  # Imprime: El área del rectángulo es: 15

En este ejemplo, calcular_area_rectangulo es una función que:

  1. Recibe dos valores (base y altura)
  2. Realiza un cálculo con ellos
  3. Devuelve el resultado

Las funciones pueden ser tan simples o complejas como necesites, pero una buena práctica es que cada función realice una única tarea específica. Esto hace que tu código sea más fácil de entender, probar y mantener.

# Función que verifica si un número es par
def es_par(numero):
    return numero % 2 == 0

# Función que convierte temperatura de Celsius a Fahrenheit
def celsius_a_fahrenheit(celsius):
    return (celsius * 9/5) + 32

En Python, las funciones son ciudadanos de primera clase, lo que significa que pueden ser:

  • Asignadas a variables
  • Pasadas como argumentos a otras funciones
  • Devueltas como resultado de otras funciones
# Asignar una función a una variable
convertir = celsius_a_fahrenheit
temperatura_f = convertir(25)  # Equivalente a celsius_a_fahrenheit(25)
print(f"25°C equivalen a {temperatura_f}°F")  # Imprime: 25°C equivalen a 77.0°F

Las funciones en Python también pueden tener un ámbito (scope), lo que significa que las variables definidas dentro de una función solo existen dentro de esa función, a menos que se devuelvan explícitamente.

def calcular_descuento(precio, porcentaje=10):
    # La variable 'descuento' solo existe dentro de esta función
    descuento = precio * (porcentaje / 100)
    precio_final = precio - descuento
    return precio_final

precio_con_descuento = calcular_descuento(100)
print(f"Precio con descuento: {precio_con_descuento}")  # Imprime: Precio con descuento: 90.0
# print(descuento)  # Esto daría error porque 'descuento' no existe fuera de la función

En resumen, las funciones son herramientas esenciales que nos permiten escribir código más organizado, reutilizable y mantenible. Son como pequeñas máquinas especializadas que podemos invocar cuando necesitamos realizar una tarea específica en nuestro programa.

Parámetros y argumentos

Los parámetros y argumentos son elementos fundamentales que permiten que nuestras funciones sean verdaderamente útiles y flexibles. Estos conceptos están relacionados pero tienen diferencias importantes que debemos entender.

Un parámetro es una variable que se define en la declaración de una función. Actúa como un espacio reservado para los datos que la función necesita para realizar su tarea. Por otro lado, un argumento es el valor real que pasamos a la función cuando la llamamos.

def saludar_persona(nombre):  # 'nombre' es un parámetro
    print(f"Hola, {nombre}!")

saludar_persona("Ana")  # "Ana" es un argumento

En este ejemplo, nombre es el parámetro (la variable que espera recibir la función) y "Ana" es el argumento (el valor concreto que le pasamos).

Tipos de parámetros

Python ofrece varios tipos de parámetros que nos dan flexibilidad al diseñar nuestras funciones:

Parámetros posicionales

Son los más básicos y se asignan según el orden en que se pasan los argumentos:

def calcular_precio_final(precio_base, impuesto):
    return precio_base + (precio_base * impuesto)

total = calcular_precio_final(100, 0.21)  # 100 va a precio_base, 0.21 va a impuesto
print(f"Precio final: {total}")  # Imprime: Precio final: 121.0

Parámetros con valores predeterminados

Permiten especificar un valor por defecto que se usará si no se proporciona un argumento:

def saludar(nombre, mensaje="¡Bienvenido!"):
    print(f"Hola {nombre}. {mensaje}")

saludar("Carlos")  # Usa el mensaje predeterminado
# Imprime: Hola Carlos. ¡Bienvenido!

saludar("María", "¿Cómo estás hoy?")  # Usa el mensaje personalizado
# Imprime: Hola María. ¿Cómo estás hoy?

Los parámetros con valores predeterminados deben aparecer después de los parámetros sin valores predeterminados:

# Correcto
def crear_perfil(nombre, edad, ciudad="Madrid"):
    return f"Perfil: {nombre}, {edad} años, {ciudad}"

# Incorrecto - causaría un error de sintaxis
# def crear_perfil(nombre, ciudad="Madrid", edad):
#     return f"Perfil: {nombre}, {edad} años, {ciudad}"

Parámetros por nombre

Podemos especificar explícitamente qué valor corresponde a cada parámetro, independientemente del orden:

def dividir(dividendo, divisor):
    return dividendo / divisor

# Usando argumentos posicionales
resultado1 = dividir(10, 2)  # resultado1 = 5.0

# Usando argumentos por nombre
resultado2 = dividir(divisor=2, dividendo=10)  # resultado2 = 5.0

Los argumentos por nombre son especialmente útiles cuando una función tiene muchos parámetros o cuando queremos hacer que nuestro código sea más legible:

def crear_usuario(nombre, apellido, edad, email, activo=True):
    return {
        "nombre_completo": f"{nombre} {apellido}",
        "edad": edad,
        "email": email,
        "activo": activo
    }

# Más fácil de leer con argumentos por nombre
usuario = crear_usuario(
    nombre="Juan",
    apellido="Pérez",
    edad=28,
    email="juan@ejemplo.com",
    activo=False
)

Combinando tipos de parámetros

Podemos combinar diferentes tipos de parámetros en una misma función:

def calcular_pago(horas, tarifa=15, moneda="EUR"):
    total = horas * tarifa
    return f"{total} {moneda}"

# Diferentes formas de llamar a la función
pago1 = calcular_pago(40)  # 40 horas, tarifa predeterminada, moneda predeterminada
pago2 = calcular_pago(35, 20)  # 35 horas, tarifa de 20, moneda predeterminada
pago3 = calcular_pago(30, moneda="USD")  # 30 horas, tarifa predeterminada, moneda USD
pago4 = calcular_pago(horas=25, tarifa=18, moneda="GBP")  # Todo especificado por nombre

print(pago1)  # Imprime: 600 EUR
print(pago2)  # Imprime: 700 EUR
print(pago3)  # Imprime: 450 USD
print(pago4)  # Imprime: 450 GBP

Validación de argumentos

Es una buena práctica validar los argumentos que recibe una función para asegurarnos de que son del tipo y valor esperados:

def calcular_descuento(precio, porcentaje):
    # Validación de argumentos
    if not isinstance(precio, (int, float)) or precio < 0:
        raise ValueError("El precio debe ser un número positivo")
    
    if not isinstance(porcentaje, (int, float)) or not (0 <= porcentaje <= 100):
        raise ValueError("El porcentaje debe ser un número entre 0 y 100")
    
    # Cálculo del descuento
    descuento = precio * (porcentaje / 100)
    return precio - descuento

try:
    precio_final = calcular_descuento(100, 15)
    print(f"Precio con descuento: {precio_final}")  # Imprime: Precio con descuento: 85.0
    
    # Esto lanzará un error
    precio_erroneo = calcular_descuento(-50, 10)
except ValueError as e:
    print(f"Error: {e}")  # Imprime: Error: El precio debe ser un número positivo

Número variable de argumentos

En ocasiones, necesitamos funciones que puedan aceptar un número variable de argumentos. Python nos ofrece dos sintaxis especiales para esto:

Argumentos posicionales variables (*args)

Permite que una función acepte cualquier número de argumentos posicionales:

def sumar(*numeros):
    total = 0
    for numero in numeros:
        total += numero
    return total

# Podemos pasar cualquier cantidad de argumentos
print(sumar(1, 2))  # Imprime: 3
print(sumar(1, 2, 3, 4, 5))  # Imprime: 15
print(sumar())  # Imprime: 0

El parámetro *numeros recibe todos los argumentos posicionales como una tupla.

Argumentos por nombre variables (**kwargs)

Permite que una función acepte cualquier número de argumentos por nombre:

def mostrar_informacion(**datos):
    for clave, valor in datos.items():
        print(f"{clave}: {valor}")

# Podemos pasar cualquier cantidad de argumentos por nombre
mostrar_informacion(nombre="Python", creador="Guido van Rossum", año=1991)
# Imprime:
# nombre: Python
# creador: Guido van Rossum
# año: 1991

El parámetro **datos recibe todos los argumentos por nombre como un diccionario.

Ejemplo práctico: Función para formatear texto

Veamos un ejemplo que combina varios tipos de parámetros para crear una función flexible:

def formatear_texto(texto, mayusculas=False, prefijo="", sufijo="", separador=" "):
    # Aplicar mayúsculas si se solicita
    if mayusculas:
        texto = texto.upper()
    
    # Dividir el texto en palabras
    palabras = texto.split()
    
    # Aplicar prefijo y sufijo a cada palabra
    palabras_formateadas = [f"{prefijo}{palabra}{sufijo}" for palabra in palabras]
    
    # Unir las palabras con el separador especificado
    resultado = separador.join(palabras_formateadas)
    
    return resultado

# Ejemplos de uso
texto_original = "python es un lenguaje versátil"

# Uso básico sin modificaciones
print(formatear_texto(texto_original))
# Imprime: python es un lenguaje versátil

# Convertir a mayúsculas
print(formatear_texto(texto_original, mayusculas=True))
# Imprime: PYTHON ES UN LENGUAJE VERSÁTIL

# Añadir prefijo y sufijo
print(formatear_texto(texto_original, prefijo="«", sufijo="»"))
# Imprime: «python» «es» «un» «lenguaje» «versátil»

# Cambiar el separador
print(formatear_texto(texto_original, separador="-"))
# Imprime: python-es-un-lenguaje-versátil

# Combinación de opciones
print(formatear_texto(
    texto_original,
    mayusculas=True,
    prefijo="#",
    sufijo="!",
    separador="..."
))
# Imprime: #PYTHON!...#ES!...#UN!...#LENGUAJE!...#VERSÁTIL!

Esta función demuestra cómo los parámetros y argumentos nos permiten crear herramientas flexibles que pueden adaptarse a diferentes necesidades sin tener que escribir código redundante.

Return

El valor de retorno es uno de los conceptos más importantes en las funciones de Python. Mientras que los parámetros permiten enviar información a una función, la sentencia return nos permite obtener resultados de ella. Podemos pensar en las funciones como pequeñas fábricas que reciben materias primas (parámetros), las procesan, y nos devuelven un producto terminado (valor de retorno).

La sentencia return cumple dos propósitos fundamentales:

  1. Devolver un valor como resultado de la función
  2. Finalizar la ejecución de la función inmediatamente
def calcular_cuadrado(numero):
    resultado = numero * numero
    return resultado  # Devuelve el valor y termina la función

area = calcular_cuadrado(4)
print(area)  # Imprime: 16

En este ejemplo, la función calcular_cuadrado recibe un número, calcula su cuadrado y lo devuelve mediante return. El valor devuelto se puede asignar a una variable (area) para usarlo posteriormente.

Funciones sin return

Si una función no incluye una sentencia return explícita, Python automáticamente devuelve None:

def saludar(nombre):
    print(f"Hola, {nombre}")
    # No hay return explícito

resultado = saludar("Laura")
print(f"La función devolvió: {resultado}")  # Imprime: La función devolvió: None

Esto muestra una distinción importante: la función saludar muestra un mensaje pero no devuelve ningún valor utilizable. Esto es adecuado para funciones que realizan acciones (como imprimir o guardar datos) pero no necesitan proporcionar un resultado.

Retornando múltiples valores

Una característica poderosa de Python es la capacidad de devolver múltiples valores desde una función:

def estadisticas(numeros):
    total = sum(numeros)
    promedio = total / len(numeros)
    minimo = min(numeros)
    maximo = max(numeros)
    return total, promedio, minimo, maximo

datos = [4, 8, 15, 16, 23, 42]
suma, media, menor, mayor = estadisticas(datos)

print(f"Suma: {suma}")        # Imprime: Suma: 108
print(f"Promedio: {media}")   # Imprime: Promedio: 18.0
print(f"Mínimo: {menor}")     # Imprime: Mínimo: 4
print(f"Máximo: {mayor}")     # Imprime: Máximo: 42

Técnicamente, Python empaqueta estos valores en una tupla que luego podemos desempaquetar en variables individuales. También podemos capturar el resultado como una única variable:

resultado = estadisticas(datos)
print(type(resultado))  # Imprime: <class 'tuple'>
print(resultado)        # Imprime: (108, 18.0, 4, 42)
print(resultado[1])     # Imprime: 18.0 (accediendo al promedio)

Return anticipado

La sentencia return finaliza inmediatamente la ejecución de la función. Esto es útil para crear salidas anticipadas cuando se cumplen ciertas condiciones:

def dividir_seguro(a, b):
    # Verificación de seguridad
    if b == 0:
        print("Error: División por cero")
        return None  # Salida anticipada
    
    # Este código solo se ejecuta si b no es cero
    resultado = a / b
    return resultado

print(dividir_seguro(10, 2))   # Imprime: 5.0
print(dividir_seguro(10, 0))   # Imprime: Error: División por cero y luego None

Esta técnica de retorno anticipado es muy útil para validaciones y manejo de casos especiales, ya que evita el anidamiento excesivo de bloques condicionales.

Patrones comunes con return

Función booleana (predicado)

Las funciones que devuelven True o False son extremadamente útiles para expresar condiciones de forma clara:

def es_mayor_de_edad(edad):
    return edad >= 18

def es_correo_valido(email):
    return "@" in email and "." in email

# Uso en condicionales
usuario_edad = 16
if es_mayor_de_edad(usuario_edad):
    print("Acceso permitido")
else:
    print("Acceso denegado")  # Imprime: Acceso denegado

Transformación de datos

Las funciones que transforman datos de un formato a otro son muy comunes:

def formato_nombre(nombre, apellido):
    return f"{apellido.upper()}, {nombre.capitalize()}"

print(formato_nombre("ana", "garcía"))  # Imprime: GARCÍA, Ana

Cálculos y procesamiento

Las funciones que realizan cálculos y devuelven resultados son la base de muchos programas:

def calcular_precio_con_iva(precio_base, tasa_iva=0.21):
    return precio_base * (1 + tasa_iva)

precio_final = calcular_precio_con_iva(100)
print(f"Precio con IVA: {precio_final} €")  # Imprime: Precio con IVA: 121.0 €

Return con estructuras de datos

Las funciones pueden devolver estructuras de datos complejas como listas, diccionarios o incluso funciones:

def crear_lista_pares(maximo):
    return [num for num in range(2, maximo + 1, 2)]

def crear_diccionario_cuadrados(numeros):
    return {num: num ** 2 for num in numeros}

pares = crear_lista_pares(10)
print(pares)  # Imprime: [2, 4, 6, 8, 10]

cuadrados = crear_diccionario_cuadrados([1, 2, 3, 4])
print(cuadrados)  # Imprime: {1: 1, 2: 4, 3: 9, 4: 16}

Buenas prácticas con return

  1. Coherencia en los tipos de retorno: Es recomendable que una función devuelva siempre el mismo tipo de datos, o tipos compatibles.
# Enfoque mejorado: siempre devuelve una lista (vacía en caso de error)
def filtrar_positivos(numeros):
    if not isinstance(numeros, list):
        return []  # Lista vacía en caso de error
    
    return [num for num in numeros if num > 0]
  1. Documentar el valor de retorno: Es importante que quede claro qué devuelve la función.
def calcular_descuento(precio, porcentaje):
    """
    Calcula el precio con descuento.
    
    Args:
        precio: El precio original
        porcentaje: El porcentaje de descuento (0-100)
        
    Returns:
        float: El precio después de aplicar el descuento
    """
    return precio - (precio * porcentaje / 100)
  1. Evitar efectos secundarios: Las funciones que devuelven valores no deberían, idealmente, modificar el estado global o realizar acciones como imprimir.
# Mejor: separar la obtención del resultado de su presentación
def calcular_promedio(numeros):
    return sum(numeros) / len(numeros)

# Uso
notas = [7, 8, 6, 9]
promedio = calcular_promedio(notas)
print(f"El promedio es: {promedio}")  # La impresión se hace fuera de la función
  1. Usar return temprano para casos especiales: Esto mejora la legibilidad del código.
def obtener_calificacion(puntuacion):
    if puntuacion < 0 or puntuacion > 100:
        return "Puntuación inválida"
    
    if puntuacion >= 90:
        return "Sobresaliente"
    if puntuacion >= 70:
        return "Notable"
    if puntuacion >= 60:
        return "Bien"
    if puntuacion >= 50:
        return "Suficiente"
    
    return "Insuficiente"

Ejemplo práctico: Función de conversión de temperatura

Veamos un ejemplo completo que ilustra el uso efectivo de return:

def convertir_temperatura(valor, origen, destino):
    """
    Convierte una temperatura entre diferentes unidades.
    
    Args:
        valor: El valor de la temperatura a convertir
        origen: Unidad de origen ('C', 'F' o 'K')
        destino: Unidad de destino ('C', 'F' o 'K')
        
    Returns:
        float: La temperatura convertida, o None si los parámetros son inválidos
    """
    # Validación de parámetros
    unidades_validas = {'C', 'F', 'K'}
    if origen not in unidades_validas or destino not in unidades_validas:
        return None
    
    # Si origen y destino son iguales, no hay conversión necesaria
    if origen == destino:
        return valor
    
    # Primero convertimos a Celsius como unidad intermedia
    if origen == 'F':
        celsius = (valor - 32) * 5/9
    elif origen == 'K':
        celsius = valor - 273.15
    else:  # origen es 'C'
        celsius = valor
    
    # Luego convertimos de Celsius a la unidad de destino
    if destino == 'F':
        return celsius * 9/5 + 32
    elif destino == 'K':
        return celsius + 273.15
    else:  # destino es 'C'
        return celsius

# Ejemplos de uso
print(convertir_temperatura(25, 'C', 'F'))    # Imprime: 77.0
print(convertir_temperatura(98.6, 'F', 'C'))  # Imprime: 37.0
print(convertir_temperatura(0, 'C', 'K'))     # Imprime: 273.15
print(convertir_temperatura(20, 'X', 'Y'))    # Imprime: None

Esta función demuestra varias buenas prácticas:

  • Validación de parámetros con retorno anticipado
  • Manejo de casos especiales (cuando origen y destino son iguales)
  • Documentación clara del valor de retorno
  • Coherencia en el tipo de retorno (siempre devuelve un número o None)

El uso efectivo de return es fundamental para crear funciones que no solo realicen tareas, sino que también proporcionen resultados útiles que podamos utilizar en otras partes de nuestro programa.

Docstrings

Los docstrings son cadenas de documentación que se utilizan en Python para describir qué hace una función, cómo usarla y qué esperar de ella. A diferencia de los comentarios regulares, los docstrings están diseñados para ser accesibles durante la ejecución del programa, lo que los convierte en una herramienta fundamental para crear código autodocumentado.

Un docstring se coloca justo después de la definición de una función, antes de cualquier otro código, y se escribe entre triples comillas (simples o dobles):

def sumar(a, b):
    """Suma dos números y devuelve el resultado."""
    return a + b

Esta simple línea de documentación ya proporciona información valiosa sobre el propósito de la función. Los docstrings bien escritos hacen que tu código sea más accesible tanto para otros desarrolladores como para ti mismo cuando revisites el código en el futuro.

Estructura básica de un docstring

Aunque Python no impone un formato específico para los docstrings, existen convenciones ampliamente aceptadas. Un docstring completo suele incluir:

  1. Una breve descripción de una línea
  2. Una descripción más detallada (opcional)
  3. Información sobre los parámetros
  4. Información sobre el valor de retorno
  5. Ejemplos o notas (opcional)
def calcular_promedio(numeros):
    """
    Calcula el promedio de una lista de números.
    
    Suma todos los números de la lista y divide el resultado
    entre la cantidad de elementos.
    
    Args:
        numeros: Una lista de valores numéricos
        
    Returns:
        El promedio como valor flotante
        
    Ejemplo:
        >>> calcular_promedio([1, 2, 3, 4])
        2.5
    """
    return sum(numeros) / len(numeros)

Accediendo a los docstrings

Una característica poderosa de los docstrings es que están disponibles en tiempo de ejecución a través del atributo __doc__ o la función help():

# Acceder al docstring directamente
print(calcular_promedio.__doc__)

# O usar la función help
help(calcular_promedio)

Esto permite que herramientas como el intérprete interactivo de Python, editores de código y generadores de documentación automática puedan mostrar esta información al programador.

Estilos de docstrings

Existen varios estilos populares para formatear docstrings. Los más comunes son:

Estilo Google

def validar_email(email):
    """
    Verifica si una dirección de correo electrónico tiene formato válido.
    
    Args:
        email (str): La dirección de correo a validar
        
    Returns:
        bool: True si el formato es válido, False en caso contrario
        
    Raises:
        TypeError: Si email no es una cadena de texto
    """
    if not isinstance(email, str):
        raise TypeError("El email debe ser una cadena de texto")
    return "@" in email and "." in email.split("@")[-1]

Estilo reStructuredText (reST)

def convertir_a_celsius(fahrenheit):
    """
    Convierte una temperatura de Fahrenheit a Celsius.
    
    :param fahrenheit: Temperatura en grados Fahrenheit
    :type fahrenheit: float
    :return: Temperatura en grados Celsius
    :rtype: float
    """
    return (fahrenheit - 32) * 5/9

Estilo NumPy/SciPy

def filtrar_pares(lista):
    """
    Filtra los números pares de una lista.
    
    Parameters
    ----------
    lista : list
        Lista de números enteros
        
    Returns
    -------
    list
        Nueva lista que contiene solo los números pares
    """
    return [num for num in lista if num % 2 == 0]

Para proyectos personales o pequeños, puedes elegir el estilo que prefieras. Para proyectos más grandes o equipos, es recomendable seguir un estilo consistente en todo el código.

Docstrings para funciones simples

Para funciones muy sencillas, un docstring de una sola línea puede ser suficiente:

def es_mayor_de_edad(edad):
    """Determina si una persona es mayor de edad (18 años o más)."""
    return edad >= 18

Sin embargo, incluso para funciones simples, un docstring más completo puede ser valioso:

def es_mayor_de_edad(edad):
    """
    Determina si una persona es mayor de edad.
    
    Args:
        edad: Edad de la persona en años
        
    Returns:
        True si la edad es 18 o mayor, False en caso contrario
    """
    return edad >= 18

Docstrings para funciones con comportamiento especial

Es especialmente útil documentar comportamientos especiales o casos límite:

def dividir_seguro(a, b):
    """
    Realiza una división segura entre dos números.
    
    Args:
        a: El numerador
        b: El denominador
        
    Returns:
        El resultado de la división a/b, o None si b es cero
        
    Ejemplo:
        >>> dividir_seguro(10, 2)
        5.0
        >>> dividir_seguro(10, 0)
        None
    """
    if b == 0:
        return None
    return a / b

Herramientas para trabajar con docstrings

Python incluye varias herramientas que aprovechan los docstrings:

  • help(): Muestra la documentación de un objeto
  • pydoc: Módulo que genera documentación a partir de docstrings
  • doctest: Permite ejecutar ejemplos incluidos en los docstrings como pruebas
def area_triangulo(base, altura):
    """
    Calcula el área de un triángulo.
    
    Args:
        base: Longitud de la base del triángulo
        altura: Altura del triángulo
        
    Returns:
        El área del triángulo
        
    Ejemplos:
        >>> area_triangulo(4, 3)
        6.0
        >>> area_triangulo(5, 8)
        20.0
    """
    return (base * altura) / 2

Estos ejemplos no solo documentan cómo usar la función, sino que también pueden ejecutarse como pruebas automáticas con el módulo doctest:

import doctest
doctest.testmod()  # Ejecuta todos los ejemplos en los docstrings como pruebas

Buenas prácticas para escribir docstrings

  1. Sé conciso pero completo: Incluye toda la información necesaria sin ser excesivamente detallado.
def generar_contraseña(longitud=8):
    """
    Genera una contraseña aleatoria.
    
    Args:
        longitud: Número de caracteres de la contraseña (predeterminado: 8)
        
    Returns:
        Una cadena con la contraseña generada
    """
    import random
    import string
    caracteres = string.ascii_letters + string.digits + string.punctuation
    return ''.join(random.choice(caracteres) for _ in range(longitud))
  1. Usa verbos en presente: Describe lo que la función hace, no lo que hará o hizo.
# Bien
def validar_usuario(nombre):
    """Verifica si el nombre de usuario cumple con los requisitos."""
    
# Evitar
def validar_usuario(nombre):
    """Esta función verificará si el nombre de usuario cumple con los requisitos."""
  1. Documenta los tipos de datos: Especifica qué tipos de datos espera la función y qué tipo devuelve.
def contar_palabras(texto):
    """
    Cuenta el número de palabras en un texto.
    
    Args:
        texto (str): El texto a analizar
        
    Returns:
        int: El número de palabras encontradas
    """
    return len(texto.split())
  1. Incluye ejemplos prácticos: Los ejemplos ayudan a entender rápidamente cómo usar la función.
def formatear_nombre(nombre, apellido):
    """
    Formatea un nombre completo en formato "Apellido, Nombre".
    
    Args:
        nombre: Nombre de la persona
        apellido: Apellido de la persona
        
    Returns:
        Cadena formateada como "Apellido, Nombre"
        
    Ejemplo:
        >>> formatear_nombre("Juan", "Pérez")
        'Pérez, Juan'
    """
    return f"{apellido}, {nombre}"
  1. Documenta excepciones: Si tu función puede lanzar excepciones, indícalo en el docstring.
def obtener_elemento(lista, indice):
    """
    Obtiene un elemento de una lista por su índice.
    
    Args:
        lista: La lista de elementos
        indice: Posición del elemento a obtener (comienza en 0)
        
    Returns:
        El elemento en la posición especificada
        
    Raises:
        IndexError: Si el índice está fuera del rango de la lista
    """
    return lista[indice]

Ejemplo práctico: Función con docstring completo

Veamos un ejemplo completo que incorpora todas las buenas prácticas:

def calcular_precio_final(precio_base, descuento=0, impuesto=0.21):
    """
    Calcula el precio final de un producto aplicando descuento e impuesto.
    
    Primero aplica el descuento sobre el precio base y luego
    añade el impuesto sobre el precio con descuento.
    
    Args:
        precio_base (float): Precio original del producto
        descuento (float, opcional): Porcentaje de descuento (0-100). Predeterminado: 0
        impuesto (float, opcional): Tasa de impuesto (0-1). Predeterminado: 0.21
        
    Returns:
        float: Precio final después de aplicar descuento e impuesto
        
    Raises:
        ValueError: Si alguno de los parámetros tiene un valor negativo
        
    Ejemplos:
        >>> calcular_precio_final(100)
        121.0
        >>> calcular_precio_final(100, 10)
        108.9
        >>> calcular_precio_final(100, 10, 0.1)
        99.0
    """
    if precio_base < 0 or descuento < 0 or impuesto < 0:
        raise ValueError("Los valores no pueden ser negativos")
    
    precio_con_descuento = precio_base * (1 - descuento/100)
    precio_final = precio_con_descuento * (1 + impuesto)
    
    return precio_final

Este docstring proporciona toda la información necesaria para usar la función correctamente:

  • Qué hace la función
  • Cómo funciona
  • Qué parámetros acepta y sus tipos
  • Valores predeterminados
  • Qué devuelve
  • Posibles errores
  • Ejemplos de uso

Conclusión práctica

Los docstrings son una inversión en la calidad y mantenibilidad de tu código. Aunque escribir buenos docstrings requiere un esfuerzo adicional, este esfuerzo se compensa con creces cuando:

  • Otros desarrolladores necesitan usar tus funciones
  • Tú mismo necesitas recordar cómo funciona tu código después de un tiempo
  • Quieres generar documentación automática para tu proyecto
  • Deseas incluir pruebas integradas en tu código

Recuerda que un buen docstring debe responder las preguntas: ¿qué hace esta función?, ¿qué necesita para funcionar? y ¿qué produce como resultado? Si tu documentación responde claramente estas preguntas, estarás creando código más accesible y fácil de mantener.

Aprende Python online

Otros ejercicios de programación de Python

Evalúa tus conocimientos de esta lección Funciones con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Módulo math

Python
Puzzle

Reto herencia

Python
Código

Excepciones

Python
Test

Introducción a Python

Python
Test

Reto variables

Python
Código

Funciones Python

Python
Puzzle

Reto funciones

Python
Código

Módulo datetime

Python
Test

Reto acumulación

Python
Código

Reto estructuras condicionales

Python
Código

Polimorfismo

Python
Test

Módulo os

Python
Test

Reto métodos dunder

Python
Código

Diccionarios

Python
Puzzle

Reto clases y objetos

Python
Código

Reto operadores

Python
Código

Operadores

Python
Test

Estructuras de control

Python
Puzzle

Funciones lambda

Python
Test

Reto diccionarios

Python
Código

Reto función lambda

Python
Código

Encapsulación

Python
Puzzle

Reto coleciones

Python
Proyecto

Reto funciones auxiliares

Python
Código

Crear módulos y paquetes

Python
Puzzle

Módulo datetime

Python
Puzzle

Excepciones

Python
Puzzle

Operadores

Python
Puzzle

Diccionarios

Python
Test

Reto map, filter

Python
Código

Reto tuplas

Python
Código

Proyecto gestor de tareas CRUD

Python
Proyecto

Tuplas

Python
Puzzle

Variables

Python
Puzzle

Tipos de datos

Python
Puzzle

Conjuntos

Python
Test

Reto mixins

Python
Código

Módulo csv

Python
Test

Módulo json

Python
Test

Herencia

Python
Test

Análisis de datos de ventas con Pandas

Python
Proyecto

Reto fechas y tiempo

Python
Proyecto

Reto estructuras de iteración

Python
Código

Funciones

Python
Test

Reto comprehensions

Python
Código

Variables

Python
Test

Reto serialización

Python
Proyecto

Módulo csv

Python
Puzzle

Reto polimorfismo

Python
Código

Polimorfismo

Python
Puzzle

Clases y objetos

Python
Código

Reto encapsulación

Python
Código

Estructuras de control

Python
Test

Importar módulos y paquetes

Python
Test

Módulo math

Python
Test

Funciones lambda

Python
Puzzle

Reto excepciones

Python
Código

Listas

Python
Puzzle

Reto archivos

Python
Proyecto

Encapsulación

Python
Test

Reto conjuntos

Python
Código

Clases y objetos

Python
Test

Instalación de Python y creación de proyecto

Python
Test

Reto listas

Python
Código

Tipos de datos

Python
Test

Crear módulos y paquetes

Python
Test

Tuplas

Python
Test

Herencia

Python
Puzzle

Reto acceso a sistema

Python
Proyecto

Proyecto sintaxis calculadora

Python
Proyecto

Importar módulos y paquetes

Python
Puzzle

Clases y objetos

Python
Puzzle

Módulo os

Python
Puzzle

Listas

Python
Test

Conjuntos

Python
Puzzle

Reto tipos de datos

Python
Código

Reto matemáticas

Python
Proyecto

Módulo json

Python
Puzzle

Todas las lecciones de Python

Accede a todas las lecciones de Python y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Python

Python

Introducción

Instalación Y Creación De Proyecto

Python

Introducción

Tema 2: Tipos De Datos, Variables Y Operadores

Python

Introducción

Instalación De Python

Python

Introducción

Tipos De Datos

Python

Sintaxis

Variables

Python

Sintaxis

Operadores

Python

Sintaxis

Estructuras De Control

Python

Sintaxis

Funciones

Python

Sintaxis

Estructuras Control Iterativo

Python

Sintaxis

Estructuras Control Condicional

Python

Sintaxis

Testing Con Pytest

Python

Sintaxis

Listas

Python

Estructuras De Datos

Tuplas

Python

Estructuras De Datos

Diccionarios

Python

Estructuras De Datos

Conjuntos

Python

Estructuras De Datos

Comprehensions

Python

Estructuras De Datos

Clases Y Objetos

Python

Programación Orientada A Objetos

Excepciones

Python

Programación Orientada A Objetos

Encapsulación

Python

Programación Orientada A Objetos

Herencia

Python

Programación Orientada A Objetos

Polimorfismo

Python

Programación Orientada A Objetos

Mixins Y Herencia Múltiple

Python

Programación Orientada A Objetos

Métodos Especiales (Dunder Methods)

Python

Programación Orientada A Objetos

Composición De Clases

Python

Programación Orientada A Objetos

Funciones Lambda

Python

Programación Funcional

Aplicación Parcial

Python

Programación Funcional

Entrada Y Salida, Manejo De Archivos

Python

Programación Funcional

Decoradores

Python

Programación Funcional

Generadores

Python

Programación Funcional

Paradigma Funcional

Python

Programación Funcional

Composición De Funciones

Python

Programación Funcional

Funciones Orden Superior Map Y Filter

Python

Programación Funcional

Funciones Auxiliares

Python

Programación Funcional

Reducción Y Acumulación

Python

Programación Funcional

Archivos Comprimidos

Python

Entrada Y Salida Io

Entrada Y Salida Avanzada

Python

Entrada Y Salida Io

Archivos Temporales

Python

Entrada Y Salida Io

Contexto With

Python

Entrada Y Salida Io

Módulo Csv

Python

Biblioteca Estándar

Módulo Json

Python

Biblioteca Estándar

Módulo Datetime

Python

Biblioteca Estándar

Módulo Math

Python

Biblioteca Estándar

Módulo Os

Python

Biblioteca Estándar

Módulo Re

Python

Biblioteca Estándar

Módulo Random

Python

Biblioteca Estándar

Módulo Time

Python

Biblioteca Estándar

Módulo Collections

Python

Biblioteca Estándar

Módulo Sys

Python

Biblioteca Estándar

Módulo Statistics

Python

Biblioteca Estándar

Módulo Pickle

Python

Biblioteca Estándar

Módulo Pathlib

Python

Biblioteca Estándar

Importar Módulos Y Paquetes

Python

Paquetes Y Módulos

Crear Módulos Y Paquetes

Python

Paquetes Y Módulos

Entornos Virtuales (Virtualenv, Venv)

Python

Entorno Y Dependencias

Gestión De Dependencias (Pip, Requirements.txt)

Python

Entorno Y Dependencias

Python-dotenv Y Variables De Entorno

Python

Entorno Y Dependencias

Acceso A Datos Con Mysql, Pymongo Y Pandas

Python

Acceso A Bases De Datos

Acceso A Mongodb Con Pymongo

Python

Acceso A Bases De Datos

Acceso A Mysql Con Mysql Connector

Python

Acceso A Bases De Datos

Novedades Python 3.13

Python

Características Modernas

Operador Walrus

Python

Características Modernas

Pattern Matching

Python

Características Modernas

Instalación Beautiful Soup

Python

Web Scraping

Sintaxis General De Beautiful Soup

Python

Web Scraping

Tipos De Selectores

Python

Web Scraping

Web Scraping De Html

Python

Web Scraping

Web Scraping Para Ciencia De Datos

Python

Web Scraping

Autenticación Y Acceso A Recursos Protegidos

Python

Web Scraping

Combinación De Selenium Con Beautiful Soup

Python

Web Scraping

Accede GRATIS a Python y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender qué es una función y cómo definirla en Python.
  • Diferenciar entre parámetros y argumentos, y conocer los tipos de parámetros.
  • Aprender a utilizar la sentencia return para devolver valores y finalizar funciones.
  • Conocer la importancia y estructura de los docstrings para documentar funciones.
  • Aplicar buenas prácticas en la creación y documentación de funciones para mejorar la legibilidad y mantenimiento del código.