Python – Y, finalmente, finally

Objetivo: presentar la cláusula finally en el manejo de excepciones en Python.

Imaginemos, por un momento, que soy un perverso programador que, bajo el aspecto de un aparente dócil y simple programa esconde en él una intención oculta. Supongamos que, aprovechándome del deseo de todo el mundo de disponer de una aplicación que permita calcular la división de dos números enteros, intento colar un sutil mensaje subliminal al ejecutarla:

dividendo = int(input('Introduce el dividendo: '))
divisor = int(input('Introduce el divisor: '))
print('El cociente de la división de ambos números es', dividendo//divisor)
print("Viva el Betis manque pierda")

>>> 
Introduce el dividendo: 10
Introduce el divisor: 2
El cociente de la división de ambos números es 5
Viva el Betis manque pierda 

Impresionante, pero no tanto…

Si por un casual introducimos como divisor un cero, la división no podrá realizarse y el programa abortará, muriendo con él también nuestras oscuras pretensiones:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
Traceback (most recent call last):
  File "C:/Python33/pruebas.py", line 3, in <module>
    print('El cociente de la división de ambos números es', dividendo//divisor)
ZeroDivisionError: integer division or modulo by zero

En los artículos anteriores presentamos la captura de excepciones en Python, de modo que tenemos recursos para solucionar esto:

try:
    dividendo = int(input('Introduce el dividendo: '))
    divisor = int(input('Introduce el divisor: '))
    print('El cociente de la división de ambos números es', dividendo//divisor)
except:
    print("No ha podido realizarse la operación")
    
print("Viva el Betis manque pierda")

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
No ha podido realizarse la operación
Viva el Betis manque pierda

Desde luego, esto funciona. La operación de división ha sido protegida con un try/except que, tal como está planteado, intercepta cualquier excepción que pudiera ocurrir. He introducido en el bloque try las dos sentencias input, no sólo la división, pues también ocurriría una excepción si se facilitase un valor no numérico cuando int() intentara la conversión a entero.

El código no fallará ante una eventual división por cero (ZeroDivisionError), la introducción de letras en vez de números (ValueError), o una interrupción con Ctrl-C (KeyboardInterrupt).

Pero no me convence. Quiero emplear mi propio manejador ante una división por cero o la introducción de letras, pero quiero respetar el gestor por omisión que trae Python (el mensaje de error clásico tras abortar el programa) para poder finalizar la ejecución con Ctrl-C si así lo deseo.

Hemos aprendido a interceptar selectivamente las excepciones también:

try:
    dividendo = int(input('Introduce el dividendo: '))
    divisor = int(input('Introduce el divisor: '))
    print('El cociente de la división de ambos números es', dividendo//divisor)
except (ZeroDivisionError, ValueError):
    print("No ha podido realizarse la operación")
    
print("Viva el Betis manque pierda")

Ahora, si dividimos entre cero, salvamos el error y también nuestro mensaje subliminal:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
No ha podido realizarse la operación
Viva el Betis manque pierda

Lo mismo si introducimos valores no numéricos:

>>> 
Introduce el dividendo: GOL!!!
No ha podido realizarse la operación
Viva el Betis manque pierda

Pero nuestro gozo en un pozo si abortamos con Ctrl-C:

>>> 
Introduce el dividendo: 
Traceback (most recent call last):
  File "C:/Python33/pruebas.py", line 2, in <module>
    dividendo = int(input('Introduce el dividendo: '))
KeyboardInterrupt

Se rompe la ejecución del programa y, con ello, el Betis pierde.

Para seguir insuflándole ánimos, Python dispone de la claúsula finally en el bloque try. El código que se incluya en ella, apúntate esto bien, se ejecutará siempre, suceda o no suceda una excepción.

En su versión más simple, finally no necesita que haya ningún except:

try:
    dividendo = int(input('Introduce el dividendo: '))
    divisor = int(input('Introduce el divisor: '))
    print('El cociente de la división de ambos números es', dividendo//divisor)
finally:
    print("Viva el Betis manque pierda")

Ahora, pase lo que pase dentro del try, la instrucción del finally se ejecutará siempre. Tanto si sucede algo bueno:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 2
El cociente de la división de ambos números es 5
Viva el Betis manque pierda

Como si no:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
Viva el Betis manque pierda
Traceback (most recent call last):
  File "C:/Python33/pruebas.py", line 4, in <module>
    print('El cociente de la división de ambos números es', dividendo//divisor)
ZeroDivisionError: integer division or modulo by zero

Se ejecuta el print del finally y, a continuación, el manejador por omisión se ocupa del tratamiento de la excepción, abortando el programa e informando por qué.

Podemos combinar finally con except también:

try:
    dividendo = int(input('Introduce el dividendo: '))
    divisor = int(input('Introduce el divisor: '))
    print('El cociente de la división de ambos números es', dividendo//divisor)
except (ZeroDivisionError, ValueError):
    print("No ha podido realizarse la operación")
finally:
    print("Viva el Betis manque pierda")

En este caso utilizamos nuestro propio gestor ante una división por cero o la introducción de valores no numéricos, pero mantenemos el que trae por defecto Python para cualquier otra excepción, lo que nos permite abortar el programa con Ctrl- C. El código dentro de la claúsula finally se ejecuta siempre, suceda o no suceda una excepción:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 4
El cociente de la división de ambos números es 2
Viva el Betis manque pierda
>>> ================================ RESTART ================================
>>> 
Introduce el dividendo: 
Viva el Betis manque pierda
Traceback (most recent call last):
  File "C:/Python33/pruebas.py", line 2, in <module>
    dividendo = int(input('Introduce el dividendo: '))
KeyboardInterrupt

El uso típico de la claúsula finally es la realización de tareas de limpieza para que no queden flecos en caso de que se produzca una excepción. Piensa, por ejemplo, en el gesto de cerrar un fichero una vez ha sido abierto para asegurarnos de que, suceda lo que suceda mientras estemos procesando el fichero, siempre quedará perfectamente cerrado.

Dedicaremos el próximo artículo, a modo de resumen, a esquematizar lo que hemos tratado hasta ahora en estos cuatro artículos dedicados a la gestión de excepciones en Python.

Nota: no soy futbolero, ni tengo preferencia por ningún equipo sobre otro, pero sí que admito un cariño y especial admiración por la afición del Betis, tan incondicional, fiel y estoica.

Javier Montero Gabarró


Python – Y, finalmente, finally


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python – Sin excepciones, what else?

Objetivo: utilización de la claúsula ELSE en la gestión de excepciones en Python.

En el artículo anterior aprendimos a capturar selectivamente excepciones y escribimos código realmente robusto que realizaba una división entera a prueba de bombas.

El programa era capaz de responder a cualquier excepción fatal. Observa las respuestas personalizadas ante una división por cero o la introducción de un valor no numérico, así como la respuesta genérica ante cualquier otra eventualidad (como el intento de abortar el programa con Ctrl-C).

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except ZeroDivisionError:
        print('¡No, no, la división por cero no está permitida')
    except ValueError:
        print('¡Ojo, presta atención e introduce sólo números!')
    except:
        print('No sé qué has hecho, pero vuelve a intentarlo')

Pero ahora voy a plantearte un sencillo ejercicio. Quiero que modifiques el programa de modo que, cada vez que el código se ejecute libre de excepciones, aparezca un mensaje indicándolo.

Obviamente, lo siguiente no sirve:

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except ZeroDivisionError:
        print('¡No, no, la división por cero no está permitida')
    except ValueError:
        print('¡Ojo, presta atención e introduce sólo números!')
    except:
        print('No sé qué has hecho, pero vuelve a intentarlo')
    print("Todo ha ido como la seda")

El mensaje aparece en cada iteración, haya o no sucedido una excepción:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 4
El cociente de la división de ambos números es 2
Todo ha ido como la seda
Introduce el dividendo: 10
Introduce el divisor: 0
¡No, no, la división por cero no está permitida
Todo ha ido como la seda
Introduce el dividendo: 

Es un problema fácil de resolver, no obstante. Podemos hacer uso de una variable booleana para alertar de que se ha producido una excepción:

while True:
    try:
        sin_excepciones = True
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except ZeroDivisionError:
        print('¡No, no, la división por cero no está permitida')
        sin_excepciones = False
    except ValueError:
        print('¡Ojo, presta atención e introduce sólo números!')
        sin_excepciones = False
    except:
        print('No sé qué has hecho, pero vuelve a intentarlo')
        sin_excepciones = False
    if sin_excepciones:
        print("Todo ha ido como la seda")

Eso es lo que haríamos en otros lenguajes como Java o C++ (pero no en C, que ni siquiera maneja excepciones). Como vemos, ahora el mensaje aparece exclusivamente sólo si el código ha transcurrido libre de tropiezos:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
¡No, no, la división por cero no está permitida
Introduce el dividendo: 10
Introduce el divisor: 4
El cociente de la división de ambos números es 2
Todo ha ido como la seda
Introduce el dividendo: 

Pero esto no es Java ni C++, sino Python…

La sentencia TRY admite una claúsula ELSE para introducir en ella el código que queremos que se ejecute siempre y cuando no haya sucedido ninguna excepción.

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except ZeroDivisionError:
        print('¡No, no, la división por cero no está permitida')
    except ValueError:
        print('¡Ojo, presta atención e introduce sólo números!')
    except:
        print('No sé qué has hecho, pero vuelve a intentarlo')
    else:
        print("Todo ha ido como la seda")

Y ahora sí…

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
¡No, no, la división por cero no está permitida
Introduce el dividendo: 10
Introduce el divisor: 4
El cociente de la división de ambos números es 2
Todo ha ido como la seda
Introduce el dividendo: 

Así de sencillo.

Seguro que George Clooney diría, si supiera programar: Python, what else?

Javier Montero Gabarró


Python – Sin excepciones, what else?


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python – Captura selectiva de excepciones

Objetivo: mostrar cómo capturar selectivamente las excepciones en Python dependiendo de su tipo.

En el artículo anterior introdujimos el concepto de excepción en Python y aprendimos a proteger a prueba de bombas un determinado bloque de código utilizando la estructura try/except. El bloque a proteger lo recogíamos en la sección try y, si algo inesperado (una excepción) ocurría dentro de él, las instrucciones contenidas en la sección except se ocupaban de su tratamiento.

Recuperemos nuestra robusta división entera:

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except:
        print('Eso no ha estado bien, pero no pasa nada')
        print('Vuelve a intentarlo')

Si y sólo si sucede una excepción dentro de la sección try, el bloque de la sección except será ejecutado.

En particular, el código está vacunado ante excepciones como, por ejemplo:

ZeroDivisionError: si introducimos un cero como divisor, la división dejará de existir.

ValueError: si en lugar de introducir números escribimos caracteres, la función int() no podrá realizar la conversión.

KeyboardInterrupt: si tecleamos Ctrl-C el programa será abortado.

Pero, ¿y si queremos controlar la captura de excepciones de un modo más selectivo? Por ejemplo, ¿cómo haríamos si sólo queremos dejar protegido el código ante un eventual ZeroDivisionError?

Basta con especificar el tipo de excepción en la claúsula except. Veámoslo:

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except ZeroDivisionError:
        print('Eso no ha estado bien, pero no pasa nada')
        print('Vuelve a intentarlo')

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
Eso no ha estado bien, pero no pasa nada
Vuelve a intentarlo
Introduce el dividendo: 
Traceback (most recent call last):
  File "C:/Users/javier/Desktop/borrable.py", line 3, in <module>
    dividendo = int(input('Introduce el dividendo: '))
KeyboardInterrupt

Como vemos, la excepción ZeroDivisionError ha sido capturada, pero no KeyboardInterrupt, ocasionada al teclear Ctrl-C con la intención de terminar la ejecución del programa.

Vayamos un paso más adelante. Escribamos ahora código que proteja no sólo de ZeroDivisionError, sino también de ValueError. Para ello, es suficiente con introducir ambas excepciones, separadas con una coma y entre paréntesis junto a la palabra except:

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except (ZeroDivisionError, ValueError):
        print('Eso no ha estado bien, pero no pasa nada')
        print('Vuelve a intentarlo')

Comprobémoslo:

>>> 
Introduce el dividendo: 12
Introduce el divisor: 0
Eso no ha estado bien, pero no pasa nada
Vuelve a intentarlo
Introduce el dividendo: 12
Introduce el divisor: abcde
Eso no ha estado bien, pero no pasa nada
Vuelve a intentarlo
Introduce el dividendo: 12
Introduce el divisor: 4
El cociente de la división de ambos números es 3
Introduce el dividendo: 
Traceback (most recent call last):
  File "C:/Users/javier/Desktop/borrable.py", line 3, in <module>
    dividendo = int(input('Introduce el dividendo: '))
KeyboardInterrupt

Ctrl-C ha podido interrumpir el programa, pero no la división por cero ni el uso de letras en lugar de números.

El código siguiente ejecutará un tratamiento diferente según la excepción que se produzca. Observa el uso de varias claúsulas except:


while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except ZeroDivisionError:
        print('¡No, no, la división por cero no está permitida!')
    except ValueError:
        print('¡Ojo, presta atención e introduce sólo números!')

No sólo hemos capturado selectivamente las excepciones ZeroDivisionError y ValueError, sino que, además, el programa responderá de modo distinto según cuál suceda. Obsérvalo:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
¡No, no, la división por cero no está permitida!
Introduce el dividendo: 10
Introduce el divisor: abcde
¡Ojo, presta atención e introduce sólo números!
Introduce el dividendo: 
Traceback (most recent call last):
  File "C:/Users/javier/Desktop/borrable.py", line 3, in <module>
    dividendo = int(input('Introduce el dividendo: '))
KeyboardInterrupt

Hemos salido del bucle infinito pulsando Ctrl-C, pues KeyboardInterrupt no ha sido capturada.

Naturalmente, puedes incluir tantos except personalizados como excepciones desees tratar.

Aún podemos rizar el rizo…

Imagina que, además de lo que hemos hecho en el ejemplo anterior, en el que hemos capturado y tratado de modo diferente dos excepciones, queremos programar una respuesta general para cualquier otra excepción. Agregamos, simplemente, una nueva claúsula except genérica que no incluya ningún nombre de excepción:

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except ZeroDivisionError:
        print('¡No, no, la división por cero no está permitida')
    except ValueError:
        print('¡Ojo, presta atención e introduce sólo números!')
    except:
        print('No sé qué has hecho, pero vuelve a intentarlo')

Y ahora:

>>> 
Introduce el dividendo: 10
Introduce el divisor: 0
¡No, no, la división por cero no está permitida
Introduce el dividendo: 10
Introduce el divisor: abcde
¡Ojo, presta atención e introduce sólo números!
Introduce el dividendo: 10
Introduce el divisor: 
No sé qué has hecho, pero vuelve a intentarlo
Introduce el dividendo: 

En el tercer intento hemos pulsado Ctrl-C, por eso aparece el mensaje que hemos reservado para otras excepciones.

El tratamiento genérico debe figurar siempre en último lugar, después de los especializados. De lo contrario, el programa devolverá un error sintáctico al tratar de ejecutarlo. Y me temo que ese tipo de errores no hay try/except que los capture.

Esto se ha puesto interesante, pero aún hay mucho más que decir sobre el tratamiento de excepciones. Permanece atento…

Javier Montero Gabarró


Python – Captura selectiva de excepciones


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python, un lenguaje excepcional

Objetivo: Introducción al manejo de excepciones en Python.

Admítelo: los errores en tiempo de ejecución suceden. Tanto si intentas abrir un fichero inexistente como si tratas de utilizar un índice fuera del rango de una lista o string, por poner dos ejemplos comunes, la respuesta de Python siempre es desagradable. Si tienes suerte y estás trabajando desde el intérprete interactivo sólo recibirás el temido mensaje de error y podrás continuar. Pero si estás ejecutando un programa éste abortará inmediatamente.

Esto casi nunca es deseable. Imagina, por ejemplo, que tu aplicación facilita un servicio importante que requiere una disponibilidad de 24 horas. El daño ocasionado por tener tu programa parado podría ser importante (económico, reputación, imagen, etc.).

Puedes intentar aprender de los errores y modificar tu programa introduciendo líneas y líneas de código hasta hacerlo inexpugnable. Puede incluso que descubras que tienes más código escrito para tratar errores que código efectivo, lo que, en cierto modo sonaría un tanto ridículo.

Pero no hace falta que tu proyecto sea de envergadura para que te preocupes por gestionar adecuadamente los eventuales errores en tiempo de ejecución. Después de todo, si has elegido Python es porque eres una persona preocupada por la elegancia programando, de modo que tienes un compromiso contigo mismo.

Para lidiar con los errores en tiempo de ejecución Python dispone de mecanismos de gestión de excepciones.

Una excepción, en el mundo de la programación, no es más que una señal que lanza el programa advirtiendo que ha sucedido algo excepcional. Lo típico es un error en tiempo de ejecución pero, como descubriremos a lo largo de estos artículos, hasta tú mismo podrías lanzar tu propia señal de excepción de un modo creativo.

Ya conoces la respuesta de Python ante una excepción provocada por un error en tiempo de ejecución: pantallazo de error y el programa aborta. Pero, ¿y si pudiéramos modificar ese comportamiento por defecto a nuestro antojo, evitando así que el programa caiga?

Es lo que se conoce como capturar la excepción. Un ejemplo sencillo aclarará esto.

El error en tiempo de ejecución de libro típico es el intento de división entre cero, una cosa muy, muy mala, que puede hacer reventar tu sistema…

El siguiente programita pide, en un bucle infinito, que introduzcas dos números para dividirlos a continuación.

while True:
    dividendo = int(input('Introduce el dividendo: '))
    divisor = int(input('Introduce el divisor: '))
    print('El cociente de la división de ambos números es', dividendo//divisor)

Vamos a jugar un poco con él:

Introduce el dividendo: 23
Introduce el divisor: 5
El cociente de la división de ambos números es 4
Introduce el dividendo: 12
Introduce el divisor: 7
El cociente de la división de ambos números es 1
Introduce el dividendo: 

Todo bien, hasta ahora. Pero, ¿qué sucede si por divisor introducimos un cero?

Introduce el dividendo: 12
Introduce el divisor: 0
Traceback (most recent call last):
  File "C:/Users/Javier/Desktop/borrable.py", line 4, in <module>
    print('El cociente de la división de ambos números es', dividendo//divisor)
ZeroDivisionError: integer division or modulo by zero

Se acabó el programa abruptamente. Se ha producido un error en tiempo de ejecución ocasionado por intentar dividir entre cero, lo que ha ocasionado que se lanzara la excepción ZeroDivisionError, como nos muestra el texto del error.

Podríamos haber hecho daño al programa de más maneras. Observa cómo introducimos los valores con la función input(), que ya sabes que devuelve un string. Por eso recurrimos después a int() para convertir ese valor en un verdadero número entero con el que poder realizar operaciones aritméticas. Pero, ¿y si no podemos convertir lo introducido a entero porque no hemos facilitado un número?

Introduce el dividendo: casa
Traceback (most recent call last):
  File "C:/Users/Javier/Desktop/borrable.py", line 2, in <module>
    dividendo = int(input('Introduce el dividendo: '))
ValueError: invalid literal for int() with base 10: 'casa'

El programa aborta también, pero está vez devuelve un error diferente. Se ha producido una excepción del tipo ValueError.

Este comportamiento no es reprochable en Python, que desconoce el efecto que podría tener mantener el programa activo pese al error sucedido. Lo más prudente es informar de lo sucedido y abortar inmediatamente la ejecución, dejando al programador (tú), si lo desea, la captura de las excepciones.

Para capturar una excepción Python dispone de la estructura try/except. En la parte try incluimos el bloque de instrucciones que queremos proteger y en el except lo que queremos que se ejecute si sucede una excepción.

Vamos a proteger el código ante los dos eventuales errores que hemos descubierto que podrían sucedernos. Por un lado hay que proteger los input y por otro la línea con el resultado de la división, de modo que en bloque try incluimos las tres líneas críticas:

while True:
    try:
        dividendo = int(input('Introduce el dividendo: '))
        divisor = int(input('Introduce el divisor: '))
        print('El cociente de la división de ambos números es', dividendo//divisor)
    except:
        print('Eso no ha estado bien, pero no pasa nada')
        print('Vuelve a intentarlo')

Presta mucha atención a la indentación, pues delimita, como siempre, la amplitud de los bloques en Python y permite saber a que try corresponde cada except.

Observa cómo, en la sección except, incluiremos código especial que sólo se ejecutará si se produce una excepción dentro del bloque protegido con try.

Vamos a verlo en acción:

Introduce el dividendo: 14
Introduce el divisor: 5
El cociente de la división de ambos números es 2
Introduce el dividendo: 35
Introduce el divisor: 0
Eso no ha estado bien, pero no pasa nada
Vuelve a intentarlo
Introduce el dividendo: 46
Introduce el divisor: casa
Eso no ha estado bien, pero no pasa nada
Vuelve a intentarlo
Introduce el dividendo: 12
Introduce el divisor: 5
El cociente de la división de ambos números es 2
Introduce el dividendo: 

Ahora sí, a prueba de bombas. ¡Está protegido incluso ante un intento de interrupción con Ctrl-C! (excepción KeyboardInterrupt).

Esto ha sido sólo un aperitivo. En los sucesivos artículos sobre excepciones iremos refinando y ampliando estos conceptos, esperando los más sofisticados a que estemos en posesión previamente de ciertos conocimientos necesarios sobre las clases y la programación orientada a objetos. Todo a su momento.

Javier Montero Gabarró


Python, un lenguaje excepcional


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies