Buscar este blog

sábado, 15 de marzo de 2025

Manejo de errores Python: Try, Except, Finally

La forma por defecto que tiene Python de manejar errores no está tan mal para un programador, pero es bastante brutal para un usuario. Detenerse bruscamente con un mensaje de error en inglés que muchas veces no entienden ni los que hablan inglés, es algo que puede mejorarse.

Funcionando en 5 minutos

El siguiente esquema es la forma más básica de manejar errores, que se puede tener funcionando en 5 minutos o menos:

divisor = 10
dividendo = 700
cociente dividendodivisor 

try:
    numero = 10
    numero += 1
    salida = f"El resultado es {numero} unidades."
    print(salida)
    if numero == 11:
        print("Al final era 11")
    else:
        print("Veo que no era 11")
        
except Exception:
    print("Ocurrió un error")

else:
    print("No hubo errores")

finally:
    print("Finalizando ordenadamente")

 

Explicación práctica

Esta explicación es suficiente para empezar ya mismo con el control de errores.

Las 4 palabras en naranja dividen el código en 4 partes bien concretas.

Estas 4 partes  se aplican sobre una porción determinada del código que puede ser la más compleja o la más crítica.

No es necesario controlar todo el archivo de código fuente (.py)

Tampoco se limita a una sola porción del código. Esta estructura puede usarse en distintas partes del mismo archivo.

Si hay una parte del código cuyos errores deseemos tener controlados, ya es un buen motivo para usarla.

try:

A continuación de try: se coloca el código cuyos errores queremos capturar.

except:

Recordemos que esta es la forma más básica, por lo tanto usamos una sola vez except: La palabra que sigue es el nombre de la clase de error que queremos controlar. Exception es la clase general, así que irá bien con cualquier error.

Debajo de except: va el código que queremos ejecutar si se produce un error.

else:

Debajo de else: va el código que queremos ejecutar si no hubo ningún error. Es opcional.

finally:

Debajo de finally: va el código que queremos ejecutar siempre, como cierre del try: Es decir, haya o no error se ejecutará.


En acción

En este punto sería bueno copiar el código de arriba, pegarlo en VS Code o el editor que usen, y modificarlo para que ocurran errores.

Por ejemplo:

  • Probar sin modificar nada, para ver cómo funciona sin errores.
  • Antes del try:, hacer que divisor valga 0. Ocurrirá un error de división por 0. Como está fuera del try:, no se controlará.
  • Luego del try:, cambiar el nombre de alguna variable o introducir alguna otro error.


Explicación teórica (pero liviana)


Excepciones

Lo que hacemos con esto se llama "capturar excepciones".

Las excepciones se producen cuando ocurre un error mientras el programa está funcionando.

Una excepción es en rigor un objeto, derivado de la clase BaseException.

Este objeto contiene información sobre un error.

Si se van a crear nuevas excepciones, no deben derivarse de BaseException sino de Exception, o incluso de subclases de ésta.

Hay clases estándar que, desde luego, derivan de Exception.

Debajo de except: se escribe el código que se va a ejecutar cuando ocurra un error de la clase que se indica luego de except.

Veamos: si el error es de tipo de datos (multiplicar dos string por ejemplo), la excepción generada será un objeto de la clase TypeError (se maneja con código que se escribe debajo de except TypeError:)

Si el error es de división por cero, la excepción generada será un objeto de la clase ZeroDivisionError (se maneja con código que se escribe debajo de except ZeroDivisionError:)

Los errores más toscos y fáciles de descubrir son los de sintaxis. (clase SyntaxError, se captura con except SyntaxError:) Por ejemplo, escribir primt en lugar de print. Esos errores no cambian. Desde que se tipeó mal ya existen y no se irán hasta que se corrija la escritura. Es más, VS Code los detecta instantáneamente.

Hay otros errores que pueden ocurrir o no. Por ejemplo:

dividendo = float(input("Ingrese el dividendo"))
divisor = float(input("Ingrese el divisor"))
cociente = divisor / dividendo

Si en este programa el usuario introduce algo distinto a 0 cuando se le pide el divisor, funcionará bien, pero si ingresa 0 se va a producir un error de división por 0.

Es decir, es un error que al momento de hacer el programa no se sabe si ocurrirá o no.


Tratamiento de errores

Como explico en esta historia, tenemos dos maneras diferentes de enfrentar los errores que no se sabe cuándo podrían suceder:

LBYL (Look Before You Leap, o mire antes de saltar)  significa que vamos a validar todo lo que se pueda. Por ejemplo, controlar que divisor no sea 0 y si lo es, emitir un mensaje y volver a pedirlo.

LBYL se ve robusto pero se gasta bastante tiempo y energía (y líneas de código) en evaluar que los datos sean correctos y las distintas condiciones estén dadas (por ejemplo, que haya espacio en disco antes de copiar un archivo)

EAFP (Easier to ask for forgiveness than permission, o es más fácil pedir perdón que permiso) significa  en forma muy simple que vamos a programar como si nada malo pudiese ocurrir, pero atención: usando try-except para capturar los errores que ocurran.

EAFP me agrada bastante porque en última instancia no se le pasa por alto ningún error. La cláusula except: puede usarse (como vimos arriba) con la clase Exception, lo que no dejará pasar ningún error, pero pueden usarse varios except: para detectar distintas clases de error y hacer el tratamiento más eficiente.


 ¿Y finally:? ¿Sirve o no sirve?

Al programador principiante puede parecerle un tanto inútil finally.

Pero el experimentado sabe que un programa empieza a hacer muchas cosas que luego debería terminar, haya o no haya un error.

Un caso típico es la escritura en archivos.

En pocas palabras, si se abre un archivo con intención de agregarle datos, luego hay que cerrarlo. Si esa operación, por ser crítica se encierra en un try:, el mejor lugar para cerrar el archivo es justamente finally: 

Como finally: se ejecuta siempre, la finalizacion perfecta para un intento de escribir en un archivo (si se controló con try:) es cerrarlo en esa parte.

Como criterio general, finally: contiene código que pone todo en orden luego de la tarea supervisada con try: Según el caso puede ser destruir objetos o variables, o reinicializarlos (volverlos al valor por defecto), cerrar archivos, enviar un mensaje, etc. etc. etc. 

 

Explicación teórica avanzada (pero útil)

Ya mostré como usar try: en 5 minutos y expliqué un poco de teoría básica.

Ahora planeo tocar temas puntuales que mejorarán tu aprovechamiento de try-except

try anidados

Los try: pueden anidarse.

Esto significa que el código que se pone entre try: y except; puede tener a su vez una parte que se controle con otro try: para capturar sus propios errores.

try:
    linea 1
    linea 2
    linea 3
 
    try:
        linea 4
        linea 5
        linea 6
        
    except TypeError:
        print("Ocurrió un error en lineas 4-6")
    
    else:
        print("No hubo errores en lineas 4-6")
    
    finally:
        print("Finalizando ordenadamente lineas 4-6")
        
except Exception:
    print("Ocurrió un error en lineas 1-6")

else:
    print("No hubo errores en lineas 1-6")

finally:
    print("Finalizando ordenadamente lineas 1-6")

En el código de arriba se ve que las lineas 1, 2 y 3 están contenidas por un try:, pero las líneas 4, 5 y 6 están a su vez dentro de otro try:

Una característica de los try: anidados:

Si el except: del try: más interno no pudiera gestionar el error (notar que hace referencia a errores de tipo) el control se va a pasar al try: exterior. Que en este ejemplo sí lo gestionaría porque hace referencia a Exception


Gestionar varios tipos de errores en un solo except:

Dijimos que los errores generan excepciones, que las excepciones son objetos, que como todo objeto tienen una clase, y que para indicar el código que las manejará debemos indicar except <clase>: 

Bien, si estuvieran en el caso de que un mismo código sirve para 2 o más clases de excepciones, pueden indicar todas juntas colocándolas dentro de una tupla 

En Python una tupla es una lista entre paréntesis.

Ejemplo:

try:

except (EOFError, MemoryError, IOError):

A primera vista parecería que le pasamos 3 argumentos entre paréntesis a except, pero no. No es una función. Lo que se le está pasando es una tupla con 3 elementos. Así "empaquetamos" y pasamos a except las clases que queremos gestionar con el código que seguirá.


Obtener información sobre el error

Por la clase de excepción que "disparó" el except: donde entró el programa ya tenemos idea de lo que causó el error, pero si usamos la muy general clase Exception o simplemente necesitamos más datos, esta es la forma de conseguirlos:

(---)




Biblio:

https://docs.python.org/3/reference/compound_stmts.html#try

https://ellibrodepython.com/excepciones-try-except-finally

https://docs.python.org/3/library/exceptions.html

https://ellibrodepython.com/definir-excepcion

https://docs.python.org/es/3.13/tutorial/errors.html

https://nipotticlaudio.blogspot.com/2024/04/es-mas-facil-pedir-perdon-que-permiso.html

 https://docs.python.org/es/3/library/exceptions.html

jueves, 13 de marzo de 2025

Instalando Visual Studio Code para Python

 


Comienzo con un par de tips que acabo de corroborar. Y a publicar sin demora.

Si luego tengo oportunidad de desarrollarla, esta historia crecerá.

La forma de obtener Visual Studio Code más fácil de recordar es buscar Visual Studio Code en un buscador (sí, por ej. Google).

¿En qué quedó mi preferencia por Spyder, aquel del que hablé en otra historia?

Me sigue gustando mucho Spyder pero también veo que Visual Studio Code es un estándar para programar en muchos lenguajes. Quien use VS Code desde antes no deberá hacer ningún esfuerzo para utilizarlo con Python.

Además está disponible para Windows, Linux (paquetes .deb y .rpm) y Mac. Imposible pasarlo por alto.

Como sea, además de buscarlo por su cuenta lo hallarán en https://code.visualstudio.com/Download

 

¿User Installer o System Installer?

Para quienes vayan a instalar VS Code en Windows surge una duda ya en la página de descargas.

¿Hay que descargar el User Installer o el System Installer?

Respuesta corta:

  • Si no se es Administrador de la computadora (tal vez porque es una PC del trabajo) o se quiere limitar VS Code a un solo Usuario, instalar User Installer
  • Si se es Administrador de la computadora (típico caso de quien lo instala en su PC del hogar o trabaja solo), usar System Installer


Extensiones recomendadas Marzo 2025

Tanto cuando aprendí a hacerlo como hoy mismo en que configuré una nueva PC, instalo Python antes que Visual Studio Code.

Y ahora sí, luego de tener Visual Studio Code abierto, instalar estas 4 extensiones ayudará muchísimo.

  • Python a grosso modo habilita la conexión entre el lenguaje Python instalado y VS Code. Permite que en la Consola de VS Code veamos nuestro programa en Python corriendo. También posibilita la depuración (deteción de errores)
    • Python Debugger (instalada automáticamente por la extensión Python
    • Pylance (instalada automáticamente por la extensión Python)
  • Prettier es la encargada de dejar espacios y otros retoques automáticos al código
  • Python Indent es la encargada de colocar las indentaciones automáticamente, detalle importante si recordamos que Python no usa llaves {} ni otros indicadores de comienzo y final de bloques, todo lo señala con indentaciones en función de las instrucciones que escribimos. Si ponemos if, la siguiente línea ya aparecerá como un bloque indentado.
  • Autopep8 PEP8 (https://peps.python.org/pep-0008) es la Guía de Estilo oficial de Python. Como los modales en la mesa, es un incordio estudiarla pero de alguna forma hay que saberla para encajar con los profesionales. Esta extensión permite que el código se formatee automáticamente al presionar Mayúsculas+Alt+F









domingo, 9 de marzo de 2025

Lo que pienso de la IA

 


Esta imagen representa lo que pienso de la Inteligencia Artificial.

Y, por cierto, fue creada con el Asistente Empresarial de Whatsapp.

Pienso que la I.A. (o A.I.) es... una herramienta.

No una herramienta más, claro está.

Es más bien una herramienta "destructiva" como en su momento lo fueron el teclado y la impresora para las máquinas de escribir (no me olvido de la PC, pero déjenme jugar con el simbolismo de estos dos elementos puros).

Lo que sucede es que la destrucción no ocurrió de un día para el otro.

Hoy día es imposible encontrar un Técnico de Máquinas de Escribir desempleado, y esto es porque ya no hay técnicos de máquinas de escribir. Nadie sufre.

Y, durante las décadas de los 80 y 90, los técnicos de Máquinas de escribir existentes tuvieron empleo suficiente y tiempo para cambiar de ocupación o directamente jubilarse.

La cosa hubiera sido más complicada para quienes comenzaran su carrera de reparación de máquinas de escribir en los 90, pero para ese momento era una opción que nadie quería tomar. (O nadie debería haber querido)

¿Se entiende a dónde voy?

En realidad no siempre pensé así. Al contrario, veía en la I.A. una terrible conspiración contra la raza humana. Sí, no es ninguna metáfora ni sarcasmo. Literalmente la consideraba el golpe maestro contra una Humanidad ya bastante atribulada.

Llegué a imaginar detalladamente escenarios perturbadores y distópicos (como en este cuento), pero fue Pat la que me devolvió a la realidad.

En resumen me hizo notar que, teniendo en cuenta la duración de una vida humana media, yo no debería preocuparme por los escenarios terminales que preveía.

Ni yo ni nadie de la época actual.

Eso sí, todo indica que los tiempos corren más de prisa que antes y que 20 años es un poco excesivo, por eso mismo una persona con 10 años de vida útil por delante no puede confiarse. Si estuviésemos en los 80s le diría que deje de pensar en reparar o utilizar máquinas de escribir, y preste toda su atención a esas raras PC que acaban de inventarse.

Tal vez en 200 años la población en la Tierra sea no de 8 mil millones de habitantes, sino de mil millones. Y la gente diga algo como ¡Qué suerte que no pasaremos nunca de mil millones! ¡Morirían de hambre! ¡No hay empleo para todos! Y sería cierto, pero no tan terrible como matar a 7 mil millones de personas, de una vez, en la actualidad. Supongo, quiero suponer, que habrían fallecido por causas naturales y el poco entusiasmo por procrear de la población¹, se encargaría del resto.

Hasta pienso que la generación del 2225 no comprendería jamás porqué podrían haber 8 mil millones de habitantes, ni qué catástrofe tendría que ocurrir para necesitar tanta gente trabajando. ¿En qué? ¿Sólo para hacer pequeñas correcciones eventuales a los procesadores/controladores de todo lo existente?


¹ Basta con observar lo que sucede en este año de 2025 respecto a 100 años atrás. Los matrimonios entre personas de 17 años de edad y los subsiguientes 14 hijos por familia, dieron paso a mucha gente soltera a los 40 años, que no tiene intención de cambiar eso ni tener ni un solo hijo. Además, siguiendo con la analogía de la máquina de escribir, pensemos que en los 60s las Compañías de Seguros tenían ejércitos  de más de 100 mecanógrafos para tipear las cláusulas y datos de cada póliza emitida, en tanto que en 2025 es el sistema informático el que genera esta información que tampoco se imprime, se consulta en línea. Otra profesión que desapareció pero nadie extraña.


Pequeño cambio cosmético

Meses de evolución y maduración han tenido su resultado: cambié un par de fuentes y colores en este blog.

Así es como la fuente Cousine que usé intencionalmente en todo para ser monótono y no distraer, le da hoy paso a dos fuentes diferentes. Tanta monotonía me abrumaba.

Para el texto aplico la muy común Verdana, y para los títulos la no menos utilizada Oswald.

En cuanto al fondo, de un negro monocromo cambié a un entre verde y azul que me parece bastante reconfortante.