Fundamentos
Tutorial Fundamentos: Depuración de programas
Identifica y soluciona errores de programación. Aprende a usar depuradores y manejo de excepciones para un código robusto y eficiente.
Aprende Fundamentos GRATIS y certifícateIdentificación de errores comunes: sintácticos, lógicos y de ejecución
En el proceso de programación, es habitual encontrarse con errores que impiden que el programa funcione correctamente. Estos errores se clasifican en sintácticos, lógicos y de ejecución. Comprender cada tipo es esencial para depurar y mejorar la calidad del código.
Los errores sintácticos ocurren cuando el código viola las reglas gramaticales del lenguaje. Por ejemplo, en PseInt, si olvidamos cerrar una estructura condicional:
Algoritmo SinFinSi
Escribir "Este programa tiene un error sintáctico"
Si verdadero Entonces
Escribir "Olvidé cerrar el Si"
FinAlgoritmo
Al ejecutar este algoritmo, PseInt mostrará un mensaje indicando que falta el FinSi. En Python, un error similar ocurre al omitir dos puntos o la indentación:
print("Este programa tiene un error sintáctico")
if True
print("Olvidé los dos puntos")
Python generará un SyntaxError señalando el punto donde se encuentra el problema. Es crucial revisar la sintaxis cuidadosamente para evitar estos errores.
Los errores lógicos se producen cuando el programa se ejecuta sin problemas, pero los resultados no son los esperados. Supongamos que queremos calcular el área de un rectángulo en PseInt:
Algoritmo AreaRectangulo
Definir base, altura, area Como Real
base <- 5
altura <- 10
area <- base / altura
Escribir "El área es: ", area
FinAlgoritmo
En lugar de multiplicar, estamos dividiendo la base entre la altura, lo cual es incorrecto. En Python, el código equivalente sería:
base = 5
altura = 10
area = base / altura
print("El área es:", area)
Para corregir el error lógico, debemos utilizar la operación adecuada:
area <- base * altura
Los errores de ejecución, o errores en tiempo de ejecución, aparecen mientras el programa se está ejecutando. Un ejemplo común es la división por cero. En PseInt:
Algoritmo DivisionCero
Definir numerador, denominador, resultado Como Real
numerador <- 10
denominador <- 0
resultado <- numerador / denominador
Escribir "El resultado es: ", resultado
FinAlgoritmo
PseInt generará un error al intentar realizar la división. En Python, el error es similar:
numerador = 10
denominador = 0
resultado = numerador / denominador
print("El resultado es:", resultado)
Python lanzará un ZeroDivisionError. Para manejar estos casos, es recomendable implementar validaciones antes de efectuar operaciones críticas:
Si denominador <> 0 Entonces
resultado <- numerador / denominador
Escribir "El resultado es: ", resultado
SiNo
Escribir "Error: división por cero"
FinSi
Identificar correctamente el tipo de error facilita su resolución. Los errores sintácticos suelen indicar exactamente dónde está el problema, gracias a los mensajes del intérprete. Los errores lógicos requieren una revisión detallada de la lógica del programa y pruebas con diferentes datos de entrada. Los errores de ejecución pueden anticiparse y evitarse mediante el uso de condicionales y gestión adecuada de situaciones excepcionales.
Es fundamental utilizar herramientas como depasos (debuggers) y agregar mensajes de impresión estratégicos para monitorear el comportamiento del programa. La atención al detalle y la práctica constante ayudan a minimizar la aparición de errores y a crear programas más robustos y eficientes.
Uso de depuradores (debuggers) y herramientas integradas
El uso de depuradores es fundamental para detectar y corregir errores en los programas. PseInt incorpora herramientas integradas que permiten realizar una ejecución controlada del código, facilitando la identificación de fallos y el entendimiento del flujo del programa.
Una de las funcionalidades clave de PseInt es la ejecución paso a paso, que permite avanzar por el programa una instrucción a la vez. Al utilizar esta opción, es posible observar cómo cambian los valores de las variables en cada paso, lo que ayuda a localizar incongruencias o errores lógicos.
Para iniciar la ejecución paso a paso, se debe seleccionar la opción "Ejecutar" en el menú principal y luego "Ejecutar paso a paso".
Consideremos el siguiente ejemplo en PseInt:
Algoritmo CalculoFactorial
Definir n, factorial Como Entero
Escribir "Introduce un número entero positivo:"
Leer n
factorial <- 1
Mientras n > 1 Hacer
factorial <- factorial * n
n <- n - 1
FinMientras
Escribir "El factorial es: ", factorial
FinAlgoritmo
Al depurar este algoritmo, podemos seguir cada iteración del bucle Mientras y observar cómo se actualizan n y factorial. Esto es especialmente útil si el resultado no es el esperado, ya que podemos identificar el paso exacto donde ocurre el problema.
Además, PseInt permite insertar puntos de ruptura o breakpoints en ciertas líneas del código. Al ejecutar el programa, la depuración se detendrá automáticamente en estos puntos, lo que es útil para saltar directamente a partes críticas del código sin tener que avanzar paso a paso desde el inicio.
Para establecer un punto de ruptura, se hace clic derecho en la línea deseada y se selecciona "Alternar punto de interrupción". Los puntos de ruptura facilitan la inspección del estado del programa en momentos específicos.
En Python, el proceso de depuración es similar y se puede realizar utilizando diversos entornos y herramientas. Por ejemplo, el módulo integrado pdb permite depurar programas desde la línea de comandos. A continuación, se muestra el código equivalente en Python:
def calculo_factorial():
n = int(input("Introduce un número entero positivo:\n"))
factorial = 1
while n > 1:
factorial *= n
n -= 1
print("El factorial es:", factorial)
calculo_factorial()
Para depurar este programa en Python usando pdb, se puede insertar la siguiente línea donde se desea iniciar la depuración:
import pdb; pdb.set_trace()
Por ejemplo:
def calculo_factorial():
n = int(input("Introduce un número entero positivo:\n"))
factorial = 1
import pdb; pdb.set_trace()
while n > 1:
factorial *= n
n -= 1
print("El factorial es:", factorial)
calculo_factorial()
Al ejecutar el programa, se iniciará el modo interactivo de depuración, permitiendo inspeccionar variables y controlar la ejecución paso a paso.
Además de pdb, existen entornos de desarrollo integrados (IDEs) como PyCharm o Visual Studio Code que ofrecen interfaces gráficas para la depuración. Estas herramientas permiten establecer puntos de interrupción, visualizar el estado de las variables y navegar por la pila de llamadas de manera intuitiva.
Volviendo a PseInt, otra característica útil es la visualización de variables en tiempo real. Durante la depuración, se muestra una ventana con los valores actuales de todas las variables definidas en el programa. Esto facilita la detección de valores inesperados o cambios no deseados.
Es importante aprovechar las herramientas integradas que proporciona PseInt para mejorar la calidad del código y acelerar el proceso de detección de errores. La combinación de la ejecución paso a paso, los puntos de ruptura y la visualización de variables conforma un conjunto poderoso para la depuración efectiva de programas.
Familiarizarse con las funciones de depuración y las herramientas integradas no solo ayuda a resolver problemas más rápidamente, sino que también contribuye a desarrollar una mejor comprensión de cómo funciona el código y cómo mejorar su eficiencia y fiabilidad.
Estrategias de prueba y diagnóstico (print statements, logs)
Las instrucciones de impresión son una herramienta sencilla y efectiva para la identificación de errores en programas. Al insertar Escribir en puntos clave del código en PseInt, es posible monitorear el valor de las variables y el flujo de ejecución del algoritmo.
Por ejemplo, si sospechamos que una variable no está tomando el valor esperado, podemos agregar una instrucción Escribir para verificar su contenido:
Algoritmo SumaNumeros
Definir a, b, suma Como Entero
a <- 5
b <- 10
suma <- a + b
Escribir "El valor de suma es: ", suma
FinAlgoritmo
Esta salida nos permite confirmar que suma contiene el resultado correcto. En caso de discrepancias, se pueden agregar más instrucciones Escribir para rastrear el origen del problema.
En Python, utilizamos la función print para el mismo propósito:
a = 5
b = 10
suma = a + b
print("El valor de suma es:", suma)
Las instrucciones de impresión ayudan a comprender cómo se modifican las variables a lo largo del programa. Al diagnosticar bucles o condiciones, es útil imprimir las variables de control o los resultados intermedios.
Supongamos que el siguiente algoritmo en PseInt no produce el resultado esperado:
Algoritmo Contador
Definir i Como Entero
Para i <- 1 Hasta 5 Hacer
Escribir "Iteración: ", i
FinPara
FinAlgoritmo
Si el ciclo no se ejecuta correctamente, podemos insertar Escribir adicionales:
Algoritmo ContadorDepurado
Definir i Como Entero
Escribir "Inicio del bucle"
Para i <- 1 Hasta 5 Hacer
Escribir "Valor de i dentro del bucle: ", i
FinPara
Escribir "Fin del bucle"
FinAlgoritmo
Así, podemos verificar el inicio y fin del bucle, y el valor de i en cada iteración. En Python, el código equivalente es:
print("Inicio del bucle")
for i in range(1, 6):
print("Valor de i dentro del bucle:", i)
print("Fin del bucle")
Una estrategia complementaria es utilizar logs para registrar información detallada durante la ejecución. Aunque PseInt no tiene una funcionalidad de logging avanzada, podemos simularla escribiendo mensajes con un formato consistente.
Por ejemplo:
Algoritmo RegistroDeEventos
Definir evento Como Cadena
evento <- "Inicio del programa"
Escribir "[INFO] ", evento
// Código del programa
evento <- "Finalización exitosa"
Escribir "[INFO] ", evento
FinAlgoritmo
Esta convención permite distinguir mensajes de log de otras salidas y facilita la lectura cuando el programa genera mucha información.
En Python, contamos con el módulo logging para manejar registros de manera más robusta:
import logging
logging.basicConfig(level=logging.INFO)
logging.info("Inicio del programa")
# Código del programa
logging.info("Finalización exitosa")
El uso del módulo logging permite ajustar el nivel de detalle de los mensajes y dirigirlos a diferentes destinos, como archivos o la consola. Es una práctica recomendada para la depuración y el mantenimiento de aplicaciones más complejas.
Al utilizar print statements y logs, es importante ser selectivo para evitar sobrecargar la salida con información innecesaria. Es conveniente enfocarse en las variables y eventos críticos para el funcionamiento del programa.
Una buena práctica es incluir mensajes en bloques de código donde es más probable que ocurran errores, como cálculos complejos o interacciones con el usuario. Esto facilita el diagnóstico y reduce el tiempo dedicado a encontrar la causa de un fallo.
Si estamos procesando una lista de datos, podemos imprimir el estado antes y después de aplicar una transformación. En Python:
lista = [2, 4, 6, 8, 10]
print("Lista original:", lista)
for i in range(len(lista)):
lista[i] *= 2
print("Lista procesada:", lista)
La revisión de la salida nos permite verificar que la transformación se ha realizado correctamente en cada elemento.
Al finalizar el proceso de prueba y diagnóstico, es recomendable eliminar o comentar las instrucciones de impresión que ya no sean necesarias. De este modo, el programa mantiene una salida limpia y profesional.
En programas más extensos, es útil implementar niveles de detalle en los logs, como debug, info, warning y error. Aunque PseInt no soporta estos niveles de forma nativa, podemos adoptar una convención similar:
Escribir "[DEBUG] Variable x =", x
Escribir "[ERROR] División por cero detectada"
En Python, el módulo logging permite especificar estos niveles y filtrar los mensajes según las necesidades:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("Variable x = %d", x)
logging.error("División por cero detectada")
Esta estrategia mejora la capacidad de diagnóstico y facilita el mantenimiento del código a largo plazo.
Las instrucciones de impresión y los logs son herramientas esenciales en el arsenal de un programador para la prueba y diagnóstico de programas. Su uso consciente y estratégico contribuye a la detección temprana de errores y al desarrollo de software más robusto y confiable.
Manejo de excepciones
En programación, el manejo de excepciones es esencial para crear aplicaciones robustas y confiables. Una excepción es un evento que interrumpe el flujo normal de un programa cuando ocurre un error o condición inesperada. Gestionar estas situaciones permite que el programa responda adecuadamente sin finalizar abruptamente.
En PseInt, aunque no existe una estructura específica para el manejo de excepciones como en otros lenguajes, es posible implementar controles para anticipar y gestionar errores. Por ejemplo, para evitar una división por cero, podemos incorporar condiciones que validen los datos antes de realizar operaciones sensibles:
Algoritmo DivisionSegura
Definir numerador, denominador, resultado Como Real
Escribir "Introduce el numerador:"
Leer numerador
Escribir "Introduce el denominador:"
Leer denominador
Si denominador = 0 Entonces
Escribir "Error: No es posible dividir entre cero."
SiNo
resultado <- numerador / denominador
Escribir "El resultado es: ", resultado
FinSi
FinAlgoritmo
En este algoritmo, verificamos si el denominador es cero antes de realizar la división, evitando así un error en tiempo de ejecución. Este tipo de validaciones son fundamentales para prevenir comportamientos inesperados.
En Python, el manejo de excepciones es más sofisticado gracias a las estructuras try, except, else y finally. Estas permiten capturar y gestionar excepciones de manera más directa y eficiente:
try:
numerador = float(input("Introduce el numerador:\n"))
denominador = float(input("Introduce el denominador:\n"))
resultado = numerador / denominador
except ZeroDivisionError:
print("Error: No es posible dividir entre cero.")
except ValueError:
print("Error: Debes introducir un número válido.")
else:
print("El resultado es:", resultado)
finally:
print("Operación finalizada.")
En este ejemplo, el bloque try contiene el código que puede generar una excepción. Si ocurre una ZeroDivisionError (división por cero) o ValueError (entrada inválida), los bloques except correspondientes manejan el error. El bloque else se ejecuta si no hay excepciones, y finally se ejecuta siempre, haya ocurrido o no una excepción. Esta estructura proporciona un control detallado sobre el flujo del programa y mejora su fiabilidad.
Otra situación común es el manejo de archivos. Al intentar abrir un archivo que no existe, se puede generar una excepción. PseInt no tiene funciones integradas avanzadas para el manejo de archivos.
En Python, se maneja mediante excepciones específicas:
try:
with open("datos.txt", "r") as archivo:
contenido = archivo.read()
except FileNotFoundError:
print("Error: El archivo no existe.")
else:
print("Contenido del archivo:")
print(contenido)
Aquí, usamos with open para abrir el archivo de forma segura. Si el archivo no se encuentra, se captura la excepción FileNotFoundError, evitando que el programa se detenga abruptamente. El uso de with también garantiza que el archivo se cierre correctamente después de su uso, mejorando la gestión de recursos.
El manejo de excepciones también es crucial en operaciones con listas o estructuras de datos.
En Python, podemos manejar esto usando excepciones:
lista = [10, 20, 30]
try:
indice = int(input("Introduce el índice al que deseas acceder (0-2):\n"))
valor = lista[indice]
except IndexError:
print("Error: Índice fuera de rango.")
except ValueError:
print("Error: Debes introducir un número entero.")
else:
print("El valor es:", valor)
Este código captura la excepción IndexError si el índice está fuera de los límites de la lista y ValueError si la entrada no es un número entero. De esta forma, el programa puede informar al usuario del problema específico y continuar ejecutándose.
Es importante documentar y lograr claridad en el manejo de excepciones. En proyectos más grandes, definir excepciones personalizadas puede ser útil para representar errores específicos de la aplicación:
class ErrorPersonalizado(Exception):
pass
def funcion_riesgosa():
# Código que puede generar un error
raise ErrorPersonalizado("Ocurrió un problema específico.")
try:
funcion_riesgosa()
except ErrorPersonalizado as e:
print("Error:", e)
Aunque en PseInt no podemos crear excepciones personalizadas, podemos diseñar el algoritmo para que devuelva códigos de error o mensajes específicos que indiquen el tipo de fallo ocurrido.
El manejo adecuado de excepciones es una práctica esencial en la programación moderna. Permite crear aplicaciones más resistentes, mejorar la experiencia del usuario y facilitar el mantenimiento y evolución del software. Al anticipar posibles errores y gestionar las excepciones de manera apropiada, se incrementa la confiabilidad y se minimiza el riesgo de fallos inesperados durante la ejecución.
Todas las lecciones de Fundamentos
Accede a todas las lecciones de Fundamentos y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
¿Qué Es La Programación?
Introducción Y Entorno
Lenguajes De Programación
Introducción Y Entorno
Ciclo De Vida Del Desarrollo De Software
Introducción Y Entorno
Herramientas Y Entornos De Desarrollo
Introducción Y Entorno
Instalar Y Configurar Pseint Y Python
Introducción Y Entorno
Estructura De Un Programa Pseint
Introducción Y Entorno
Pensamiento Algorítmico
Lógica
Tipos De Datos Y Variables
Lógica
Operadores
Lógica
Estructuras De Control Condicional
Lógica
Estructuras De Control De Repetición
Lógica
Diagramas De Flujo
Lógica
Depuración De Programas
Lógica
Arrays
Estructuras De Datos
Matrices
Estructuras De Datos
Cadenas De Caracteres
Estructuras De Datos
Algoritmos De Ordenamiento
Ordenamiento Y Búsqueda
Algoritmos De Búsqueda
Ordenamiento Y Búsqueda
Complejidad Temporal Y Espacial
Ordenamiento Y Búsqueda
Definición Y Utilidad De Las Funciones
Funciones
Paso De Parámetros
Funciones
Recursividad
Funciones
Funciones Anónimas
Funciones
Concepto De Clases Y Objetos
Programación Orientada A Objetos
Método Constructor
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Composición
Programación Orientada A Objetos
En esta lección
Objetivos de aprendizaje de esta lección
- Entender los errores sintácticos, lógicos y de ejecución.
- Utilizar depuradores para encontrar y corregir errores.
- Implementar estrategias de prueba y diagnóstico eficaz.
- Manejar excepciones para mejorar la estabilidad del código.