2011-01-22 41 views
10

Xin chào mọi người, tôi đang làm việc trên một dự án cào dữ liệu và tôi đang tìm một cách sạch sẽ để lặp lại một cuộc gọi hàm nếu một ngoại lệ được nâng lên.Lặp lại lời gọi hàm Python trên ngoại lệ?

Pseudo-code:

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

Tôi nhận ra đây không phải là thực hành tốt nhất tại tất cả nhưng tôi đang làm việc thông qua một số lớp mã/mạng khác nhau mà không phải là đáng tin cậy và tôi có thể không thực tế gỡ lỗi chúng.

Hiện tại tôi đang hoàn thành công việc này với một bộ rất lớn thử \ trừ khối và làm cho mắt tôi chảy máu.

Ý tưởng thanh lịch cho bất kỳ ai?

+1

Đây là một tình huống mà một goto sẽ vô cùng hữu ích. –

+8

@Rafe: Không, nó thực sự sẽ không. –

+4

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

Trả lời

11

Để làm được một cách chính xác những gì bạn muốn, bạn có thể làm một cái gì đó như sau:

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 

Sau đó, bạn chỉ cần quấn chức năng cũ trong hàm mới này:

#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

Sử dụng functools.wraps thay vì thay đổi \ _ \ _ name \ _ \ _. –

+0

@Fred Đã cập nhật để sử dụng. – user470379

+2

Tuyệt. Tôi thực sự đã kết thúc bằng cách sử dụng http://peter-hoffmann.com/2010/retry-decorator-python.html nhưng nó khá nhiều ý tưởng tương tự. – Haipa

0

Hãy thử sau đoạn:

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

Nhưng nó là tốt hơn để hạn chế số lượng lần thử lại.

+0

'ngoại trừ:' không phải là một ý tưởng hay trong hầu hết các trường hợp (* nhưng không phải tất cả *). Tôi muốn sử dụng 'ngoại trừ ngoại lệ:'. Và điều này tất nhiên giả định rằng 'func()' sẽ chấm dứt ở tất cả. – AndiDog

8

Sử dụng một vòng lặp

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

Bạn có thể có nghĩa là 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 

Hope this helps

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

Chỉ là những gì tôi đang tìm kiếm. Cảm ơn! –

1

Tôi thích làm những vấn đề này với đệ quy:

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

Nâng ngoại lệ như bình thường sau khi n thử lại

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() 
Các vấn đề liên quan