Cuando todo es una excepción

Estándar

Hoy os vengo a hablar de algo que me ha pasado personalmente trabajando con Python. Si vienes de un lenguaje de programación compilado, te habrás visto, como yo, envuelto en ciertas situaciones en las que tu código funciona perfectamente hasta el punto en el que cierta parte es ejecutada y contiene un error. Estos errores en tiempo de ejecución son difíciles de encontrar y de evitar en muchas ocasiones, y los despistes comunes que podamos tener no aydudan.

En un lenguaje como Python en el que la gran mayoría de esos errores, que otros lenguajes lanzarían en tiempo de compilación, son excepciones, hemos de ser especialmente cautos con nuestro control de éstas, o podemos encontrarnos con casos como el siguiente:

if __name__ == "__main__":
    var = 1
    try:
        new_var = wrong_var + 1
        print('Your new var value: {0}'.format(new_var))
    except:
        pass

El código por supuesto es una versión muy simplificada de lo que podría ser un programa real, pero la captura de de cualquier tipo de excepción es una técnica real que se utiliza en muchos casos. En este ejemplo, wrong_var podría ser un residuo de una refactorización de la variable new_var, que cambió de nombre, pero no en todas sus apariciones en el script. En este caso nuestro script no proporcionaría ningún tipo de aviso o mensaje que nos advierta de este error, dado que el bloque de captura de la excepción elimina esa posibilidad.

Repito, en este caso ese bloque no tiene mucho sentido, pero estoy seguro que en otro tipo de situaciones puede parecer una buena idea. Mejor pensárselo dos veces.

Anuncios

[Python] Recurring Timer

Estándar

Hoy os dejo un pequeño snippet de código en Python para disponer de un temporizador recurrente que ejecute una función cada cierta cantidad de tiempo. Python dispone de un temporizador en el módulo Threading, pero sólo se puede utilizar para ejecutar la función después de pasada el tiempo de espera configurado, sin volver a repetirse.

class RecurringTimer(threading._Timer):
    """ Own implementation of timer to make it recurring

    Timer (based on threading._Timer)
    that invokes a method at a certain interval of seconds

    """
    
    def __init__ (self, *args, **kwargs):
        threading._Timer.__init__ (self, *args, **kwargs) 
        self.setDaemon (True)
        self._running = 0
        self._destroy = 0
        self.start()

    def run (self):
        while True:
            self.finished.wait (self.interval)
            if self._destroy:
                return;
            if self._running:
                self.function (*self.args, **self.kwargs)

    def start_timer (self):
        self._running = 1

    def stop_timer (self):
        self._running = 0

    def is_running (self):
        return self._running

    def destroy_timer (self):
        self._destroy = 1;

Como podéis ver, nos aprovechamos de la propia clase _Timer del módulo Threading (ya que Timer una función de conveniencia para crear una instancia de la clase _Timer) y reimplementamos el método run para hacer esperar al hilo la cantidad de tiempo necesaria y ejecutar el método si el temporizador no ha sido cancelado.

Lo podemos ejecutar de la siguiente manera:

if __name__ == "__main__":
    def sayhi (name):
        print 'hi %s' % name

    t = RecurringTimer(1.0, sayhi, ['alex952'])
    t.start_timer()

Este ejecución imprimirá hi alex952 cada segundo, de manera indefinida. Si deseamos parar el timer para poder reanudarlo posteriormente, los métodos stop_timer y start_timer están disponibles, y si, por el contrario deseamos deshacernos por completo del hilo que ocupa el temporizador, lo podemos hacer llamando el método destroy_timer.

Espero que os resulte de ayuda 🙂