============================ Sesión 6 - Funciones en Python ============================ Introducción ============ Hasta ahora hemos aprendido sobre tipos de datos básicos (int, float, bool, str), operadores, estructuras de control (if, elif, else), ciclos (while, for), y listas. Estos elementos nos permiten escribir programas, pero a medida que estos crecen en complejidad, es necesario organizar nuestro código para hacerlo más legible, reutilizable y fácil de mantener. Aquí es donde entran las **funciones**. Las funciones son bloques de código que realizan una tarea específica y pueden ser reutilizados en diferentes partes de un programa. Son fundamentales para la programación modular, donde dividimos un problema grande en partes más pequeñas y manejables. Definición de Funciones ======================= En Python, definimos una función usando la palabra clave ``def``, seguida del nombre de la función y paréntesis que pueden contener parámetros. La definición termina con dos puntos (``:``) y el cuerpo de la función debe estar indentado. Sintaxis básica: .. code-block:: python def nombre_funcion(parametro1, parametro2, ...): # Cuerpo de la función # Código que realiza una tarea específica return valor # Opcional **Ejemplo simple:** .. code-block:: python def saludar(): print("¡Hola, mundo!") # Llamada a la función saludar() # Imprime: ¡Hola, mundo! Parámetros y Argumentos ======================= Los **parámetros** son variables que se definen en la declaración de la función, mientras que los **argumentos** son los valores que se pasan a la función cuando se llama. .. code-block:: python def saludar_persona(nombre): # 'nombre' es un parámetro print(f"¡Hola, {nombre}!") saludar_persona("Ana") # "Ana" es un argumento saludar_persona("Carlos") # "Carlos" es un argumento Múltiples parámetros: .. code-block:: python def describir_persona(nombre, edad, ciudad): print(f"{nombre} tiene {edad} años y vive en {ciudad}.") describir_persona("Juan", 25, "Bogotá") Parámetros con Valores por Defecto ---------------------------------- Python permite asignar valores predeterminados (por defecto) a los parámetros, lo que hace que sean opcionales al momento de llamar a la función. .. code-block:: python def saludar(nombre, mensaje="¡Hola!"): print(f"{mensaje} {nombre}") saludar("María") # Usa el mensaje por defecto: ¡Hola! María saludar("Pedro", "¡Buenos días!") # Usa el mensaje personalizado: ¡Buenos días! Pedro Esto es especialmente útil cuando una función tiene muchos parámetros, pero la mayoría de las veces solo se necesitan algunos de ellos: .. code-block:: python def crear_descripcion(nombre, edad, ciudad="Desconocida", profesion="No especificada"): return f"{nombre} tiene {edad} años, vive en {ciudad} y trabaja como {profesion}." # Solo proporcionamos nombre y edad, usando valores por defecto para los demás perfil1 = crear_descripcion("Ana", 28) print(perfil1) # Ana tiene 28 años, vive en Desconocida y trabaja como No especificada. # Especificamos todos los valores perfil2 = crear_descripcion("Carlos", 35, "Madrid", "Ingeniero") print(perfil2) # Carlos tiene 35 años, vive en Madrid y trabaja como Ingeniero. # Podemos omitir algunos parámetros intermedios usando argumentos nombrados perfil3 = crear_descripcion("Laura", 42, profesion="Doctora") print(perfil3) # Laura tiene 42 años, vive en Desconocida y trabaja como Doctora. **Consideraciones importantes:** 1. Los parámetros con valores por defecto deben definirse después de los parámetros sin valores por defecto. 2. Los valores por defecto se evalúan solo una vez, cuando se define la función. 3. Para objetos mutables (como listas o diccionarios), es recomendable usar ``None`` como valor por defecto y luego inicializar el objeto dentro de la función: .. code-block:: python # Forma correcta def añadir_item(item, lista=None): if lista is None: lista = [] lista.append(item) return lista # Forma incorrecta (puede causar comportamientos inesperados) def añadir_item_incorrecto(item, lista=[]): lista.append(item) return lista # Demostración print(añadir_item(1)) # [1] print(añadir_item(2)) # [2] print(añadir_item_incorrecto(1)) # [1] print(añadir_item_incorrecto(2)) # [1, 2] - ¡La lista se comparte entre llamadas! Valores de Retorno ================= Las funciones pueden devolver valores usando la palabra clave ``return``. Una vez que se ejecuta una declaración ``return``, la función termina y devuelve el valor especificado. .. code-block:: python def sumar(a, b): resultado = a + b return resultado total = sumar(5, 3) # total = 8 print(total) # Imprime: 8 Una función puede devolver múltiples valores como una tupla: .. code-block:: python def operaciones_basicas(a, b): suma = a + b resta = a - b return suma, resta # Devuelve una tupla s, r = operaciones_basicas(10, 4) print(f"Suma: {s}, Resta: {r}") # Imprime: Suma: 14, Resta: 6 Docstrings ========= Las **docstrings** son cadenas de texto que se colocan justo después de la definición de una función y sirven para documentar qué hace la función, qué parámetros recibe y qué valor retorna. Usar docstrings es una buena práctica porque hace que el código sea más comprensible y facilita su mantenimiento. Sintaxis básica: .. code-block:: python def nombre_funcion(parametros): """ Descripción de lo que hace la función. Args: param1: Descripción del primer parámetro param2: Descripción del segundo parámetro Returns: Descripción de lo que retorna la función """ # Cuerpo de la función return resultado **Ejemplo:** .. code-block:: python def calcular_area_circulo(radio): """ Calcula el área de un círculo. Args: radio: El radio del círculo en unidades arbitrarias Returns: El área del círculo """ import math return math.pi * radio ** 2 # Acceder a la docstring print(calcular_area_circulo.__doc__) # También puedes usar la función help() help(calcular_area_circulo) Los docstrings son accesibles a través de la propiedad ``__doc__`` de la función o mediante la función ``help()``. Esto permite que otros programadores (o tú mismo en el futuro) entiendan cómo usar tu función sin tener que leer todo su código. Anotaciones de Tipo (Type Hints) ================================ Python es un lenguaje de tipado dinámico, lo que significa que no necesitas declarar el tipo de una variable cuando la creas. Sin embargo, a partir de Python 3.5, se introdujeron las **anotaciones de tipo** (type hints), que permiten indicar de manera explícita qué tipos de datos se esperan como parámetros y qué tipo de dato se retorna en una función. Las anotaciones de tipo no afectan la ejecución del programa, pero son útiles por varias razones: 1. **Documentación**: Hacen el código más legible y autodocumentado 2. **Validación**: Herramientas como mypy pueden verificar posibles errores de tipo 3. **Compatibilidad con IDEs**: Mejoran las sugerencias de autocompletado y la detección de errores en editores como PyCharm, VSCode, etc. Sintaxis básica: .. code-block:: python def nombre_funcion(parametro1: tipo1, parametro2: tipo2) -> tipo_retorno: # Cuerpo de la función return valor **Ejemplos:** .. code-block:: python def saludar(nombre: str) -> str: return f"Hola, {nombre}!" def sumar(a: int, b: int) -> int: return a + b def es_mayor_de_edad(edad: int) -> bool: return edad >= 18 Para tipos más complejos como listas, diccionarios o tipos opcionales, se utiliza el módulo `typing`: .. code-block:: python from typing import List, Optional, Tuple def procesar_numeros(numeros: List[float]) -> float: """Calcula el promedio de una lista de números.""" return sum(numeros) / len(numeros) def obtener_usuario(id_usuario: int) -> Optional[str]: """ Busca un usuario por su ID. Retorna None si no se encuentra, o un string con la información si existe. """ # Simulación de búsqueda if id_usuario > 0: return f"Usuario con ID {id_usuario}, edad: 25 años" return None def operaciones(a: int, b: int) -> Tuple[int, int, float]: """Realiza suma, resta y división entre dos números.""" suma = a + b resta = a - b division = a / b if b != 0 else 0 return suma, resta, division Las anotaciones de tipo hacen que tu código sea más profesional, facilitan el trabajo en equipo y ayudan a prevenir errores comunes de tipo durante el desarrollo. Manejo de Errores en Funciones ============================= Cuando escribimos funciones, es importante considerar los posibles errores que pueden ocurrir durante su ejecución. Python proporciona el mecanismo ``try``/``except`` para manejar excepciones y hacer que nuestras funciones sean más robustas. Sintaxis básica: .. code-block:: python def funcion(): try: # Código que puede generar una excepción resultado = operacion_riesgosa() return resultado except TipoDeExcepcion: # Código para manejar la excepción return valor_alternativo **Ejemplo práctico:** .. code-block:: python def dividir(a: float, b: float) -> float: """ Divide dos números con manejo de error para división por cero. Args: a: Numerador b: Denominador Returns: El resultado de la división, o 0 si hay división por cero """ try: return a / b except ZeroDivisionError: print("Error: No es posible dividir por cero") return 0 # Retornamos un valor por defecto # Ejemplo de uso: print(dividir(10, 2)) # 5.0 print(dividir(10, 0)) # Imprime mensaje de error y retorna 0 El manejo de errores es especialmente útil cuando: 1. Trabajamos con entrada de usuario 2. Realizamos operaciones matemáticas que pueden causar errores (división por cero, raíz cuadrada de números negativos, etc.) 3. Accedemos a recursos externos como archivos o conexiones de red 4. Procesamos datos de formato desconocido o variable Funciones Lambda =============== Las **funciones lambda** (o funciones anónimas) permiten crear funciones pequeñas y de un solo uso de forma concisa, sin necesidad de utilizar la sintaxis completa de ``def``. Son útiles especialmente cuando necesitamos pasar una función simple como argumento a otra función. Sintaxis básica: .. code-block:: python lambda parametros: expresion **Ejemplos:** .. code-block:: python # Función lambda que calcula el cuadrado de un número cuadrado = lambda x: x**2 # Equivalente usando def def cuadrado_normal(x): return x**2 # Uso de la función lambda print(cuadrado(5)) # 25 # Lambda con múltiples parámetros suma = lambda a, b: a + b print(suma(3, 4)) # 7 # Uso común con funciones como map() numeros = [1, 2, 3, 4, 5] cuadrados = list(map(lambda x: x**2, numeros)) print(cuadrados) # [1, 4, 9, 16, 25] # Uso con filter() numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] pares = list(filter(lambda x: x % 2 == 0, numeros)) print(pares) # [2, 4, 6, 8, 10] **Limitaciones de las funciones lambda:** 1. Solo pueden contener una expresión (no múltiples líneas de código) 2. No se pueden incluir declaraciones (como `if`, `for`, etc.) de forma directa 3. No tienen nombre, lo que dificulta la depuración 4. No permiten docstrings Las funciones lambda son ideales para operaciones simples, pero para lógica más compleja es mejor usar funciones normales definidas con ``def``. Funciones de Alto Orden ====================== Las **funciones de alto orden** son funciones que pueden recibir otras funciones como parámetros o que retornan funciones como resultado. Este concepto es fundamental en la programación funcional y Python lo soporta completamente. Funciones que Reciben Funciones ------------------------------ Muchas funciones integradas en Python funcionan de esta manera: .. code-block:: python def aplicar_operacion(func, valor): """ Aplica una función a un valor dado. Args: func: La función a aplicar valor: El valor sobre el cual aplicar la función Returns: El resultado de aplicar func a valor """ return func(valor) # Usando la función con diferentes operaciones def cuadrado(x): return x * x def doble(x): return x * 2 print(aplicar_operacion(cuadrado, 5)) # 25 print(aplicar_operacion(doble, 5)) # 10 print(aplicar_operacion(lambda x: x + 10, 5)) # 15 Funciones Integradas de Alto Orden -------------------------------- Python incluye varias funciones de alto orden muy útiles: 1. **map()**: Aplica una función a cada elemento de un iterable .. code-block:: python numeros = [1, 2, 3, 4, 5] cuadrados = list(map(lambda x: x**2, numeros)) print(cuadrados) # [1, 4, 9, 16, 25] # Equivalente con comprensión de listas cuadrados_comp = [x**2 for x in numeros] 2. **filter()**: Filtra elementos de un iterable según una función que retorna booleanos .. code-block:: python numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] pares = list(filter(lambda x: x % 2 == 0, numeros)) print(pares) # [2, 4, 6, 8, 10] # Equivalente con comprensión de listas pares_comp = [x for x in numeros if x % 2 == 0] 3. **sorted()**: Ordena un iterable utilizando una función clave opcional .. code-block:: python # Lista de tuplas (nombre, promedio) estudiantes = [ ("Ana", 9.5), ("Carlos", 8.2), ("María", 9.8) ] # Ordenar por promedio (de mayor a menor) ordenados = sorted(estudiantes, key=lambda estudiante: estudiante[1], reverse=True) for nombre, promedio in ordenados: print(f"{nombre}: {promedio}") # Otro ejemplo: ordenar palabras por su longitud palabras = ["python", "es", "un", "lenguaje", "poderoso"] palabras_ordenadas = sorted(palabras, key=len) print(palabras_ordenadas) # ['es', 'un', 'python', 'lenguaje', 'poderoso'] 4. **reduce()**: Aplica una función a pares de elementos para reducirlos a un solo valor .. code-block:: python from functools import reduce numeros = [1, 2, 3, 4, 5] producto = reduce(lambda x, y: x * y, numeros) print(producto) # 120 (1*2*3*4*5) Funciones que Retornan Funciones ------------------------------ También podemos crear funciones que devuelven otras funciones, lo que permite crear **clausuras** (closures) y **fábricas de funciones**: .. code-block:: python def crear_multiplicador(factor): """ Crea y retorna una función que multiplica por el factor dado. Args: factor: El número por el cual multiplicar Returns: Una función que toma un número y lo multiplica por factor """ def multiplicador(x): return x * factor return multiplicador duplicar = crear_multiplicador(2) triplicar = crear_multiplicador(3) print(duplicar(5)) # 10 print(triplicar(5)) # 15 Este patrón es muy útil para crear funciones especializadas a partir de funciones más generales, lo que aumenta la reutilización del código. Alcance de Variables (Scope) ============================ El **alcance** de una variable se refiere a la región del programa donde la variable es accesible. En Python, existen principalmente dos tipos de alcance: 1. **Local**: Variables definidas dentro de una función 2. **Global**: Variables definidas en el nivel principal del programa .. code-block:: python x = 10 # Variable global def funcion(): y = 5 # Variable local print(x) # Puede acceder a la variable global print(y) # Puede acceder a la variable local funcion() print(x) # Puede acceder a la variable global # print(y) # Error: y no está definida fuera de la función Si intentamos modificar una variable global dentro de una función, Python creará una nueva variable local con el mismo nombre. Para modificar una variable global, debemos usar la palabra clave ``global``: .. code-block:: python contador = 0 def incrementar(): global contador # Indica que usaremos la variable global contador += 1 incrementar() print(contador) # Imprime: 1 Mejores Prácticas para Funciones ================================ Al escribir funciones en Python, seguir estas prácticas recomendadas te ayudará a crear código más limpio, mantenible y eficiente: 1. **Nombres descriptivos**: Usa nombres claros que describan lo que hace la función. - ✅ `calcular_area_triangulo()` - ❌ `cal_a()` o `funcion1()` 2. **Responsabilidad única**: Cada función debe hacer una sola cosa y hacerla bien. - ✅ Funciones pequeñas y enfocadas - ❌ Funciones que hacen múltiples tareas no relacionadas 3. **Longitud adecuada**: Intenta mantener tus funciones cortas (15-20 líneas como máximo). - Si una función es muy larga, probablemente pueda dividirse en funciones más pequeñas. 4. **Número de parámetros**: Limita el número de parámetros (idealmente 4 o menos). - Demasiados parámetros dificultan la legibilidad y el uso de la función. - Considera usar un diccionario para múltiples parámetros opcionales. 5. **Valores por defecto razonables**: Usa valores por defecto que sean útiles para el caso más común. 6. **Evita efectos secundarios**: Las funciones no deberían modificar variables globales o cambiar valores de entrada. - ✅ Retornar un nuevo objeto con cambios - ❌ Modificar directamente un objeto pasado como parámetro (a menos que sea el propósito explícito) 7. **Manejo de errores adecuado**: Anticipa posibles errores y manéjalos apropiadamente. - Usa try/except cuando sea necesario - Valida entradas al inicio de la función 8. **Documentación clara**: Escribe docstrings que expliquen el propósito, parámetros y valores de retorno. 9. **Consistencia en el estilo**: Mantén un estilo coherente en todas tus funciones. - Sigue PEP 8 para la convención de nombres (snake_case para funciones) 10. **DRY (Don't Repeat Yourself)**: Si encuentras código duplicado, es una señal de que deberías crear una función. 11. **Early return**: Devuelve resultados temprano para casos especiales o errores, evitando anidación excesiva. .. code-block:: python # Mejor (con early return) def procesar_dato(valor): if valor < 0: return None # Early return para caso especial # Continuar con el procesamiento normal resultado = valor * 2 return resultado # Peor (sin early return) def procesar_dato(valor): if valor >= 0: resultado = valor * 2 return resultado else: return None Siguiendo estas prácticas, tu código será más legible, mantenible y tendrás menos errores, lo que se traduce en menos tiempo de depuración y más productividad. Ejercicios Prácticos ================== Ejercicio 1: Distancia Euclidiana --------------------------------- Escribe una función que calcule la distancia euclidiana entre dos puntos en un plano 2D. La función debe recibir las coordenadas (x1, y1) y (x2, y2) como parámetros. .. toggle:: .. code-block:: python def distancia_euclidiana(x1: float, y1: float, x2: float, y2: float) -> float: """ Calcula la distancia euclidiana entre dos puntos (x1, y1) y (x2, y2). Args: x1: Coordenada x del primer punto y1: Coordenada y del primer punto x2: Coordenada x del segundo punto y2: Coordenada y del segundo punto Returns: La distancia euclidiana entre los dos puntos """ import math dx = x2 - x1 dy = y2 - y1 return math.sqrt(dx**2 + dy**2) # Ejemplo de uso: # distancia = distancia_euclidiana(1, 2, 4, 6) # print(f"La distancia es: {distancia}") # Imprime: La distancia es: 5.0 Ejercicio 2: Invertir una Cadena -------------------------------- Implementa una función que invierta una cadena de texto. .. toggle:: .. code-block:: python def invertir_cadena(texto: str) -> str: """ Invierte el orden de los caracteres en una cadena. Args: texto: La cadena a invertir Returns: La cadena invertida """ return texto[::-1] # Ejemplo de uso: # original = "Python" # invertida = invertir_cadena(original) # print(f"Original: {original}, Invertida: {invertida}") # # Imprime: Original: Python, Invertida: nohtyP Ejercicio 3: Suma de una Lista ------------------------------ Escribe una función que calcule la suma de todos los elementos de una lista. .. toggle:: .. code-block:: python from typing import List def sumar_lista(numeros: List[float]) -> float: """ Suma todos los elementos de una lista. Args: numeros: Lista de números a sumar Returns: La suma de todos los elementos """ total = 0 for num in numeros: total += num return total # Ejemplo de uso: # lista = [1, 2, 3, 4, 5] # suma = sumar_lista(lista) # print(f"La suma de {lista} es: {suma}") # Imprime: La suma de [1, 2, 3, 4, 5] es: 15 Ejercicio 4: Verificación de Número Primo ----------------------------------------- Crea una función que verifique si un número es primo. .. toggle:: .. code-block:: python def es_primo(numero: int) -> bool: """ Verifica si un número es primo. Args: numero: El número a verificar Returns: True si el número es primo, False en caso contrario """ if numero <= 1: return False if numero == 2: return True if numero % 2 == 0: return False # Verificamos solo los divisores impares hasta la raíz cuadrada i = 3 while i * i <= numero: if numero % i == 0: return False i += 2 return True # Ejemplo de uso: # for n in range(1, 21): # print(f"{n} es primo: {es_primo(n)}") Ejercicio 5: Convertidor de Temperatura --------------------------------------- Escribe dos funciones: una que convierta de grados Celsius a Fahrenheit y otra que haga la conversión inversa. .. toggle:: .. code-block:: python def celsius_a_fahrenheit(celsius: float) -> float: """ Convierte una temperatura de grados Celsius a Fahrenheit. Args: celsius: Temperatura en grados Celsius Returns: Temperatura en grados Fahrenheit """ return (celsius * 9/5) + 32 def fahrenheit_a_celsius(fahrenheit: float) -> float: """ Convierte una temperatura de grados Fahrenheit a Celsius. Args: fahrenheit: Temperatura en grados Fahrenheit Returns: Temperatura en grados Celsius """ return (fahrenheit - 32) * 5/9 # Ejemplo de uso: # temp_c = 25 # temp_f = celsius_a_fahrenheit(temp_c) # print(f"{temp_c}°C = {temp_f}°F") # # temp_f = 98.6 # temp_c = fahrenheit_a_celsius(temp_f) # print(f"{temp_f}°F = {temp_c}°C") Ejercicio 6: Factorial ---------------------- Implementa una función que calcule el factorial de un número entero no negativo. .. toggle:: .. code-block:: python def factorial(n: int) -> int: """ Calcula el factorial de un número entero no negativo. Args: n: Número entero no negativo Returns: El factorial de n Raises: ValueError: Si n es negativo """ if n < 0: raise ValueError("El factorial no está definido para números negativos") if n == 0 or n == 1: return 1 resultado = 1 for i in range(2, n + 1): resultado *= i return resultado # Ejemplo de uso: # for i in range(6): # print(f"{i}! = {factorial(i)}") Ejercicio 7: Contador de Vocales -------------------------------- Crea una función que cuente el número de vocales en una cadena de texto. .. toggle:: .. code-block:: python def contar_vocales(texto: str) -> int: """ Cuenta el número de vocales en una cadena de texto. Args: texto: La cadena de texto a analizar Returns: El número de vocales encontradas """ vocales = "aeiouAEIOU" contador = 0 for caracter in texto: if caracter in vocales: contador += 1 return contador # Ejemplo de uso: # texto = "Hola, mundo" # num_vocales = contar_vocales(texto) # print(f"'{texto}' tiene {num_vocales} vocales") Ejercicio 8: Máximo Común Divisor --------------------------------- Implementa una función que calcule el MCD de dos números utilizando el algoritmo de Euclides. .. toggle:: .. code-block:: python def mcd(a: int, b: int) -> int: """ Calcula el máximo común divisor de dos números enteros usando el algoritmo de Euclides. Args: a: Primer número entero b: Segundo número entero Returns: El máximo común divisor de a y b """ while b: a, b = b, a % b return a # Ejemplo de uso: # print(f"MCD de 48 y 18: {mcd(48, 18)}") # Debería imprimir 6 Ejercicio 9: Validador de Contraseñas ------------------------------------- Desarrolla una función que verifique si una contraseña cumple con ciertos criterios: - Longitud mínima de 8 caracteres - Al menos una letra mayúscula - Al menos una letra minúscula - Al menos un número .. toggle:: .. code-block:: python from typing import Tuple def validar_contrasena(contrasena: str) -> Tuple[bool, str]: """ Verifica si una contraseña cumple con los criterios de seguridad. Args: contrasena: La contraseña a validar Returns: Una tupla con un booleano (True si es válida) y un mensaje descriptivo """ if len(contrasena) < 8: return False, "La contraseña debe tener al menos 8 caracteres" if not any(c.isupper() for c in contrasena): return False, "La contraseña debe contener al menos una letra mayúscula" if not any(c.islower() for c in contrasena): return False, "La contraseña debe contener al menos una letra minúscula" if not any(c.isdigit() for c in contrasena): return False, "La contraseña debe contener al menos un número" return True, "Contraseña válida" # Ejemplo de uso: # contrasenas = ["abc123", "Abc123", "ABCdef", "Abcdef123"] # for c in contrasenas: # valida, mensaje = validar_contrasena(c) # print(f"'{c}': {mensaje}") Ejercicio 10: Función con Parámetros por Defecto ------------------------------------------------ Crea una función para generar un mensaje personalizado que incluya los parámetros: nombre, edad, y ocupación, donde edad y ocupación tengan valores por defecto. .. toggle:: .. code-block:: python from typing import Optional def generar_presentacion(nombre: str, edad: Optional[int] = None, ocupacion: str = "estudiante") -> str: """ Genera un mensaje de presentación personalizado. Args: nombre: Nombre de la persona edad: Edad de la persona. Por defecto None (no se menciona) ocupacion: Ocupación de la persona. Por defecto "estudiante" Returns: Un mensaje de presentación personalizado """ mensaje = f"Hola, me llamo {nombre}" if edad is not None: mensaje += f" y tengo {edad} años" mensaje += f". Soy {ocupacion}." return mensaje # Ejemplo de uso: # print(generar_presentacion("Ana")) # # Output: Hola, me llamo Ana. Soy estudiante. # # print(generar_presentacion("Carlos", 28)) # # Output: Hola, me llamo Carlos y tengo 28 años. Soy estudiante. # # print(generar_presentacion("Laura", ocupacion="ingeniera")) # # Output: Hola, me llamo Laura. Soy ingeniera. # # print(generar_presentacion("Miguel", 42, "profesor")) # # Output: Hola, me llamo Miguel y tengo 42 años. Soy profesor. Conclusión ========== Las funciones son una herramienta fundamental en Python y en la programación en general. Nos permiten: - **Modularizar** nuestro código - **Reutilizar** bloques de código - Hacer nuestro código más **legible** y **mantenible** - **Abstraer** la complejidad Los parámetros por defecto aumentan la flexibilidad de nuestras funciones, permitiendo que tengan comportamientos predeterminados cuando no se proporcionan todos los argumentos. Las docstrings, anotaciones de tipo y el manejo adecuado de errores nos ayudan a escribir código más robusto y profesional. Las funciones lambda nos proporcionan una forma concisa de definir funciones simples cuando es necesario. En la robótica y programación en Webots, las funciones nos ayudarán a organizar nuestro código para controlar sensores, actuadores y comportamientos del robot de manera más estructurada y eficiente. Recuerda siempre documentar tus funciones y seguir las convenciones de Python para nombrarlas (nombres en minúsculas separados por guiones bajos). Referencias =========== - `Documentación oficial de Python sobre funciones `_ - `PEP 8 -- Style Guide for Python Code `_ - `Documentación sobre docstrings (PEP 257) `_ - `Type hints en Python (PEP 484) `_