Fundamentos de programación T3
|
|
Título del Test:
![]() Fundamentos de programación T3 Descripción: Fundamentos de programación T3 |



| Comentarios |
|---|
NO HAY REGISTROS |
|
Una ingeniera de software está diseñando una API para un servicio de mapas. Otros equipos de la empresa consumirán esta API para integrar funcionalidades de mapas en sus propias aplicaciones. La ingeniera debe decidir cómo diseñar la función principal obtener_ruta(). Quiere que sea potente y flexible, pero también fácil de usar para los casos más comunes, como simplemente obtener la ruta más rápida entre dos puntos en coche. Al definir la función def obtener_ruta(origen, destino, modo='coche', evitar_peajes=False, hora_salida=None):, ¿qué concepto clave está aplicando para mejorar la usabilidad y flexibilidad de la función?. Sobrecarga de funciones, permitiendo que existan múltiples funciones con el mismo nombre pero diferentes implementaciones, de modo que el sistema elige cuál usar basándose en el número de argumentos proporcionados. El uso de variables globales para modo, evitar_peajes y hora_salida, de forma que el desarrollador que use la función pueda configurarlas una vez al inicio de su programa y no tenga que pasarlas en cada llamada. El uso de parámetros posicionales obligatorios para todos los argumentos, forzando al programador que la utiliza a especificar siempre todos los detalles de la ruta para evitar ambigüedades y errores. El uso de parámetros con valores por defecto, que permite a los usuarios llamar a la función con solo los argumentos esenciales (origen y destino) mientras que da la flexibilidad de personalizar el comportamiento cuando sea necesario. Un equipo de desarrollo de software está construyendo una biblioteca para un sistema de e-commerce. Un programador junior ha creado una función procesar_pago(datos_tarjeta,direccion_envio,detalles_pedido,id_usuario). Al revisarla, un desarrollador senior sugiere rediseñarla. Propone crear una función de más alto nivel, realizar_compra(pedido), que internamente llame a otras funciones más específicas como validar_pedido(), cobrar_tarjeta() y registrar_envio(), sin que el usuario de la función principal necesite conocer esos detalles. ¿Qué concepto clave de la programación se está utilizando al ocultar la complejidad de los subprocesos de pago detrás de la función realizar_compra(pedido)?. La recursividad, ya que la función realizar_compra se llama a sí misma indirectamente a través de las otras funciones para procesar el estado del pago hasta que se completa la transacción. La abstracción, que permite ocultar los detalles de implementación de un proceso complejo, permitiendo que otras partes del sistema interactúen con la función sin necesidad de conocer su funcionamiento interno. El polimorfismo, que permitiría que la función realizar_compra se comporte de manera diferente según el tipo de objeto "pedido" que reciba, aunque en este caso el enfoque principal es la ocultación de la complejidad. El acoplamiento fuerte, donde se asegura que la función realizar_compra y las funciones internas estén tan interconectadas que cualquier cambio en una requiera cambios en las demás para garantizar la integridad del proceso de pago. Durante una revisión de código en una empresa de desarrollo, se analiza una función destinada a generar un informe de actividad de usuario. La función actual tiene más de 200 líneas y realiza múltiples tareas: se conecta a la base de datos, extrae los registros, los procesa para calcular estadísticas, formatea los datos en una tabla HTML y finalmente envía el informe por correo electrónico. El líder técnico ha marcado esta función como "no mantenible". ¿Cuál sería la estrategia correcta para rediseñar esta función y mejorar la estructura del software?. Añadir comentarios exhaustivos a cada bloque lógico de la función para que, aunque sea larga, cualquier programador pueda entender lo que hace cada parte sin necesidad de modificarla. Dividir la función en dos mitades: una para la obtención de datos y otra para la presentación, manteniendo ambas en el mismo archivo para no crear demasiados módulos y complicar las importaciones. Convertir la función en una clase y cada una de las tareas en métodos privados, ya que la orientación a objetos siempre es superior a la programación procedimental para cualquier tipo de problema. Descomponer la función monolítica en varias funciones más pequeñas y con una única responsabilidad, como obtener_datos_usuario(), calcular_estadisticas(), formatear_informe_html() y enviar_correo(), y luego orquestar su llamada desde una función principal. Una startup de tecnología financiera está desarrollando una nueva plataforma de análisis de inversiones. El sistema debe gestionar datos de mercado en tiempo real, perfiles de usuario, carteras de inversión y generar informes complejos. El arquitecto de software principal insiste en que la primera fase del proyecto no debe centrarse en escribir código de inmediato, sino en definir los grandes bloques funcionales del sistema, como "Gestión de Usuarios", "Procesamiento de Datos" y "Generación de Informes", para luego descomponer cada uno en tareas más pequeñas. ¿Qué principio fundamental del diseño de software está aplicando el arquitecto para garantizar que un proyecto tan complejo sea manejable y escalable a largo plazo?. El principio de optimización prematura, que busca la máxima eficiencia del código desde el inicio del proyecto, asegurando que los componentes de más bajo nivel sean lo más rápidos posible antes de construir la lógica de alto nivel. Una metodología de desarrollo ágil (Scrum), centrada exclusivamente en la entrega rápida de funcionalidades pequeñas e incrementales, sin necesidad de una planificación estructural previa de todo el sistema. El uso de programación extrema (XP), que prioriza la programación en parejas y la integración continua del código por encima de la fase de diseño jerárquico, permitiendo que la estructura emerja orgánicamente. La estrategia de diseño descendente, que consiste en descomponer un sistema complejo en subproblemas más pequeños y manejables de forma jerárquica, facilitando la planificación, el desarrollo y la mantenibilidad del software. Una empresa de logística necesita un programa para calcular el coste de envío de paquetes. Las reglas de negocio son: el coste base es de 5€, se añade un extra de 2€ si el peso supera los 10 kg, y otro extra de 10€ si el destino es internacional. Un programador ha escrito el mismo bloque de código if-elif-else para calcular este coste en tres partes distintas del sistema (en el módulo de ventas, en el de devoluciones y en el de simulación de envíos). Desde la perspectiva del diseño de software, ¿cuál es la mejor solución para refactorizar este código y por qué mejora la calidad del sistema?. Crear tres variables globales (coste_base, extra_peso, extra_internacional) para que sean accesibles desde cualquier parte del código, evitando así tener que pasar parámetros y simplificando las llamadas. Mover todo el código repetido a un único script que se ejecute al inicio del programa, calculando todos los costes posibles y almacenándolos en un diccionario para su posterior consulta. Definir una función calcular_coste_envio(peso, es_internacional) que encapsule la lógica del cálculo y devuelva el coste total. Reduciendo la redundancia y facilitando el mantenimiento. Implementar una estructura de control switch-case (simulada en Python con if-elif-else) dentro de cada módulo, pero utilizando comentarios detallados para explicar la lógica, mejorando así la legibilidad sin alterar la estructura del código existente. Un equipo de desarrollo está trabajando en un sistema de configuración de servidores. Han definido una función configurar_servidor(nombre, ip, so='Linux', ram=8, almacenamiento=256). Un nuevo requisito exige que la configuración se aplique en un orden específico: primero el nombre, luego el sistema operativo y finalmente la IP. Sin embargo, un programador realiza la siguiente llamada: configurar_servidor(ip='192.168.1.10', nombre='db-server-01', so='Ubuntu'). ¿Qué característica de los parámetros de función en Python permite que la llamada anterior funcione correctamente a pesar de no seguir el orden de definición y qué evalúa esta habilidad?. Los parámetros arbitrarios (*args), que recogen todos los argumentos posicionales en una tupla, permitiendo que el orden no importe siempre que todos los valores requeridos estén presentes. Los parámetros por nombre (keyword arguments), que permiten pasar valores a una función especificando explícitamente a qué parámetro corresponde cada valor. La coerción de tipos, donde Python convierte automáticamente los argumentos al tipo de dato esperado por la función, independientemente del nombre o la posición en que se pasen. La validación de precondiciones, que comprueba antes de la ejecución que todos los parámetros necesarios han sido proporcionados, sin importar si se hizo por posición o por nombre. En un sistema de gestión de usuarios, existe una variable global intentos_login = 0. Una función verificar_credenciales(usuario, clave) debe incrementar esta variable global cada vez que se produce un intento fallido. El programador escribe el siguiente código: def verificar_credenciales(...): if fallo: intentos_login = intentos_login + 1. Al ejecutarlo, el programa lanza un UnboundLocalError. ¿Por qué se produce este error y cuál es la explicación correcta sobre cómo Python maneja los ámbitos de variables en este caso?. Python asume que intentos_login es una variable local. Al intentar leerla (intentos_login + 1) antes de que se le haya asignado un valor en el ámbito local, se produce el error. Se necesita la palabra clave global para resolverlo. El error ocurre porque las variables globales son de solo lectura por defecto dentro de las funciones, y cualquier intento de escritura, incluso para leer su valor en una asignación, está prohibido sin excepción. El UnboundLocalError se debe a un conflicto de tipos, ya que la variable global intentos_login es un entero y la función intenta crear una variable local de otro tipo con el mismo nombre. El intérprete de Python requiere que todas las variables usadas dentro de una función sean pasadas como parámetros, y prohíbe el acceso a variables del ámbito global para promover un diseño más modular y sin efectos secundarios. Un equipo está desarrollando una aplicación que requiere procesar listas de números para obtener el valor más alto, el más bajo y la suma total. Un programador está a punto de escribir tres funciones desde cero: una para encontrar el máximo, otra para el mínimo y una para sumar los elementos. Un compañero con más experiencia le sugiere que no reinvente la rueda y aproveche las herramientas que ya ofrece el lenguaje. ¿Qué tipo de funciones debería utilizar el programador para resolver esta tarea de forma eficiente y estándar en Python?. Funciones anónimas (lambda) para definir rápidamente las operaciones max, min y sum en una sola línea, ya que son más eficientes que las funciones normales para operaciones matemáticas. Funciones importadas del módulo math, como math.max() y math.sum(), que están optimizadas para cálculos numéricos de alta precisión y son la opción estándar para estas operaciones. Funciones integradas (built-in) como max(), min() y sum(), que están disponibles directamente en el intérprete de Python sin necesidad de importaciones y están altamente optimizadas para estas tareas comunes. Métodos de la clase list, como lista.maximo() o lista.sumar(), que son la forma orientada a objetos de realizar estas operaciones directamente sobre el objeto de la lista. Estás desarrollando un módulo de análisis de datos que debe procesar ficheros de texto. Quieres crear una función analizar_fichero() que pueda aceptar una lista variable de operaciones a realizar sobre el texto, como 'contar_palabras', 'buscar_urls' o 'calcular_frecuencia_letras'. No sabes de antemano cuántas ni cuáles operaciones querrá realizar el usuario en cada llamada a la función. ¿Qué tipo de parámetro deberías usar en la definición de tu función def analizar_fichero(ruta_fichero, ...): para permitir que reciba un número indeterminado de operaciones como argumentos posicionales?. Un parámetro operaciones de tipo lista, forzando al usuario a agrupar todas las operaciones en una lista antes de llamar a la función, como en analizar_fichero('data.txt',['contar_palabras','buscar_urls']). Un parámetro de tipo argumento arbitrario posicional (*args), como def analizar_fichero(ruta_fichero, *operaciones):, que agrupará todas las operaciones extra pasadas como argumentos en una tupla. Múltiples parámetros con valores por defecto, como op1=None, op2=None, op3=None. 0. Un parámetro de tipo argumento arbitrario por nombre (**kwargs), que permitiría pasar las operaciones con un nombre. Estás trabajando en el desarrollo de un módulo de utilidades matemáticas. Creas una función para calcular la potencia de un número, potencia(base, exponente). Sin embargo, un compañero de tu equipo intenta llamarla usando potencia(5). El programa falla con un TypeError, porque la función esperaba dos argumentos y solo recibió uno. Para hacer la función más robusta y versátil, decides que si el exponente no se especifica, la función debería calcular el cuadrado del número. ¿Cómo deberías modificar la declaración de la función para implementar este comportamiento y qué concepto de diseño de funciones estás aplicando?. Modificar la declaración de la función para incluir un valor por defecto para el exponente, como def potencia(base, exponente=2):. Utilizar un bloque try-except dentro de la función para capturar el TypeError y, si se produce, asignar a exponente el valor 2. Crear una segunda función llamada cuadrado(base) y pedirle a tu equipo que use esa en lugar de potencia cuando solo tengan un argumento. Usar *args en la definición, def potencia(*args):, y luego comprobar la longitud de args dentro de la función. Un programador está depurando un sistema complejo y encuentra una función llamada procesar_datos(x, y, z). Para entender qué hace, tiene que leer todo su código interno. La función no tiene comentarios ni documentación. Para mejorar la mantenibilidad y facilitar la colaboración, el líder del equipo le pide que documente adecuadamente la función, especificando qué hace, qué representan sus parámetros y qué devuelve. ¿Cuál es la forma estándar y profesional en Python para añadir esta documentación directamente en la función de manera que herramientas automáticas y la ayuda interactiva (help()) puedan utilizarla?. Incluir un docstring (una cadena de texto multilínea entre triples comillas) justo al principio del cuerpo de la función. Añadir comentarios de una sola línea (#) encima de la definición de la función, explicando detalladamente su funcionamiento. Crear un documento de texto separado (README.md) en la misma carpeta que el script, explicando el propósito de cada función del módulo. Usar anotaciones de tipo (type hints) para los parámetros y el valor de retorno. Estás desarrollando una función crítica para un sistema de transacciones bancarias que calcula el interés compuesto. La función calcular_interes(capital, tasa, periodos) debe asegurar bajo cualquier circunstancia que no se procesen valores inválidos, como una tasa negativa o un número de periodos igual a cero. Un error en estos cálculos podría tener consecuencias financieras graves, por lo que la función debe fallar de forma inmediata y explícita si los datos de entrada no son correctos. ¿Cuál es la mejor manera de implementar un "contrato" en la función para garantizar que las condiciones de entrada se cumplan antes de ejecutar la lógica principal?. Confiar en que el código que llama a la función siempre proporcionará datos válidos, siguiendo el principio de "garbage in, garbage out" y asumiendo que la validación es responsabilidad del cliente. Usar una serie de sentencias if que impriman mensajes de advertencia en la consola si los datos son incorrectos, pero que permitan que la función continúe su ejecución, devolviendo None o 0. Establecer precondiciones utilizando sentencias assert al inicio de la función (ej. assert tasa > 0, "La tasa de interés debe ser positiva"), que detendrán la ejecución con un AssertionError si una condición no se cumple. Envolver toda la lógica de la función en un bloque try...except Exception para capturar cualquier error matemático que pueda ocurrir durante el cálculo y registrarlo en un archivo de log sin detener el programa. Un programador junior está trabajando en una aplicación de procesamiento de imágenes. Ha definido una variable global CONFIG_BRILLO = 1.2 al inicio de su script. Dentro de una función ajustar_brillo(imagen), intenta modificar este valor con la línea CONFIG_BRILLO = 1.5 para que todas las futuras llamadas a cualquier función usen la nueva configuración. Sin embargo, al ejecutar el código, el valor de la variable global no cambia fuera de la función, y en su lugar se ha creado una nueva variable local. ¿Qué está fallando y qué implicación de diseño tiene esta solución?. Se debe usar la palabra clave local para indicar que, aunque el nombre coincide con una variable global, la intención es trabajar con una versión local. Se debe declarar global CONFIG_BRILLO al inicio de la función. Esto aumenta el acoplamiento y puede generar efectos secundarios difíciles de rastrear. Se necesita la función set() para poder cambiar el valor de una variable que está fuera del ámbito actual, como en set(CONFIG_BRILLO, 1.5). La función debe retornar el nuevo valor y el código fuera de la función debe reasignar la variable global: CONFIG_BRILLO = ajustar_brillo(imagen). Una empresa está desarrollando un sistema de generación de informes personalizables. La función principal generar_informe() debe aceptar una serie de metadatos que pueden variar mucho entre informes. Por ejemplo, un informe financiero podría necesitar {'autor': 'Ana', 'departamento': 'Ventas', 'moneda': 'EUR'}, mientras que un informe técnico podría requerir {'version_software': '2.1', 'revisor': 'Carlos'}. Se necesita una forma de capturar toda esta información flexible en la firma de la función. ¿Cuál es la forma más idiomática y profesional en Python de definir la función generar_informe para que pueda aceptar cualquier número de estos pares clave-valor como metadatos?. Usar *args para capturar todos los metadatos y luego procesar la tupla resultante. Definir la función con una gran cantidad de parámetros opcionales (autor=None, departamento=None, moneda=None, ...). Requerir que todos los metadatos se pasen en un único argumento de tipo string formateado en JSON. Usar un parámetro de tipo argumento arbitrario por nombre (**kwargs), que recogerá todos los argumentos en un diccionario. Un ingeniero de software está diseñando una función validar_usuario(username, password). La función debe verificar que el nombre de usuario tenga al menos 4 caracteres y que la contraseña no sea una de las 100 contraseñas más comunes (almacenadas en una lista llamada passwords_comunes). La función debe devolver True solo si ambas condiciones se cumplen. El ingeniero quiere escribir el código de la forma más concisa y legible posible. ¿Cuál de las siguientes implementaciones utiliza correctamente las funciones integradas y los operadores lógicos para reflejar las reglas de negocio de forma clara y eficiente?. Una implementación con if-elif-else anidados que comprueba cada condición por separado y tiene múltiples puntos de retorno. Usar un bucle for para iterar sobre la lista de contraseñas comunes y una variable flag para registrar si la contraseña se encuentra, y otro if para la longitud del nombre de usuario. Una función lambda que intenta encapsular toda la lógica en una sola línea. Una única sentencia return que combina las condiciones usando operadores lógicos y funciones integradas: return len(username) >= 4 and password not in passwords_comunes. |





