2011-01-22 9 views
10

Hola a todos, estoy trabajando en un proyecto de raspado de datos y estoy buscando una manera limpia de repetir una llamada de función si se produce una excepción.¿Se repite la llamada a la función de Python con excepción?

Pseudo-código:

try: 
    myfunc(x) 
except myError: 
    ###try to call myfunc(x) again Y number of times, 
     until success(no exceptions raised) otherwise raise myError2 

Me di cuenta que no es la mejor práctica en absoluto, sino que estoy trabajando a través de un número de diferentes capas de código/de red que no son fiables y no es realista depurarlos.

Ahora estoy logrando esto con una gran cantidad de bloques de prueba \ excepto y me está haciendo sangrar los ojos.

Elegant ideas anyone?

+1

Esta es una situación en la que un Goto sería increíblemente útil. –

+8

@Rafe: No, realmente no lo haría. –

+4

['from __past__ import goto'] (http://entrian.com/goto/) – AndiDog

Respuesta

11

Para ello, precisamente, lo que quiere, se puede hacer algo como lo siguiente:

import functools 
def try_x_times(x, exceptions_to_catch, exception_to_raise, fn): 
    @functools.wraps(fn) #keeps name and docstring of old function 
    def new_fn(*args, **kwargs): 
     for i in xrange(x): 
      try: 
       return fn(*args, **kwargs) 
      except exceptions_to_catch: 
       pass 
     raise exception_to_raise 
    return new_fn 

A continuación, sólo envolver la función anterior en esta nueva función:

#instead of 
#risky_method(1,2,'x') 
not_so_risky_method = try_x_times(3, (MyError,), myError2, risky_method) 
not_so_risky_method(1,2,'x') 

#or just 
try_x_times(3, (MyError,), myError2, risky_method)(1,2,'x') 
+2

Use functools.wraps en lugar de cambiar \ _ \ _ name \ _ \ _ usted mismo. –

+0

@Fred Actualizado para usarlo. – user470379

+2

Cool. De hecho, terminé usando http://peter-hoffmann.com/2010/retry-decorator-python.html pero es más o menos la misma idea. – Haipa

0

Try siguiente fragmento:

while True: 
    try: 
     func() 
     break 
    except: 
     print "Error. Gonna try again" 

Pero es mejor limitar el número de reintentos.

+0

'excepto:' no es una buena idea en la mayoría de los casos (* pero no en todos *). Prefiero usar 'excepto Exception:'. Y esto, por supuesto, asume que 'func()' terminará en absoluto. – AndiDog

8

utilizar un bucle

i = 0 
while True: 
    try: myfunc(x); break; 
    except myError: 
    i = i + 1; 
    # print "Trying again" 
    if i > 5: raise myError2; 
+0

Probablemente quiera decir i> 5. :) –

0
success = False 
attempts = 0 
while not success and attempts < 10: # or however many times you want to attempt 
    try: 
     functionCall() 
     success = True 
    except: 
     i += 1 
if not success: 
    raise functionCallFailedError 

Esperanza esto ayuda

4

for x in xrange(num_retries): 
    try: 
     myFunc() 
    except MyError, err: 
     continue 
     #time.sleep(1) 
    err = None 
    break 
if err: 
    raise MyError2 
#else: 
# print "Success!" 


+0

Justo lo que estaba buscando. ¡Gracias! –

1

me gusta hacer estos problemas con la recursividad:

def tryfor(times, on_failure, excepts, func, *args, **kwargs): 
    if times < 1: 
     raise on_failure() 
    try: 
     return func(*args, **kwargs) 
    except excepts: 
     return tryfor(times-1, on_failure, excepts, func, *args, **kwargs) 


tryfor(3, PermanentException, (SomeError,), dostuff,1,2) 
0

Para elevar Excepción como de costumbre después de N tentativas

from functools import wraps 

def retry(times): 
    """ 
    Decorator to retry any functions 'times' times. 
    """ 
    def retry_decorator(func): 
     @wraps(func) 
     def retried_function(*args, **kwargs): 
      for i in range(times - 1): 
       try: 
        func(*args, **kwargs) 
        return 
       except Exception: 
        pass 
      func(*args, **kwargs) 

     return retried_function 

    return retry_decorator 


# test 

attempts = 3 

@retry(4) 
def function_that_raises_error(): 
    global attempts 
    if 0 < attempts: 
     print("fail") 
     attempts -= 1 
     raise Exception 

    print("pass") 

function_that_raises_error() 
Cuestiones relacionadas