2017-09-29 1 views
0

파이썬에서 작업을 시도하고 있는데 실패한 경우 특정 방식으로 최대 10 번 시도하고 싶습니다. 다른 방법으로 이 실패하면 즉시 실패하고 싶습니다. 10 번의 재시도 후에 모든 실패가 발신자에게 전파되기를 바랍니다.조건부로 작업을 다시 시도하기위한 파이썬 흐름 제어

나는 흐름 제어를 만족스러운 방법으로 코딩 할 수 없었다. 여기에 행동의 한 예입니다 내가 원하는 (하지만 스타일!) :

def run(): 
    max_retries = 10 
    for retry_index in range(max_retries): 
     try: 
      result = run_operation() 
     except OneTypeOfError: 
      if retry_index < max_retries - 1: 
       continue 
      else: 
       raise 

     if result.another_type_of_error: 
      if retry_index < max_retries - 1: 
       continue 
      else: 
       raise AnotherTypeOfError() 

     try: 
      result.do_a_followup_operation() 
     except AThirdTypeOfError: 
      if retry_index < max_retries - 1: 
       continue 
      else: 
       raise 

     return result 

    raise Exception("We don't expect to end up here") 

가 처음에 난 그냥이 그렇게 재시도 논리 오류 처리 논리에서 분리 된 리팩토링 수 있다고 생각. 문제는, 예를 들어, OneTypeOfError가 result.do_a_followup_operation()에 의해 발생된다면, 나는 그 경우에 전혀 재 시도하지 않기를 바란다. 위의 특정 상황에서만 다시 시도하고 싶습니다.

그래서이 결과를 반환하는 함수, 제기 된 Exception (있는 경우) 및 다시 시도 가능한 예외인지 여부를 나타내는 플래그로 리펙토링 할 수 있다고 생각했습니다. 여하튼 그것은 나에게 상기보다 덜 우아하다고 느꼈다.

여기에 도움이 될만한 파이썬에서 흐름 제어 패턴이 있는지 궁금합니다.

+1

당신은 [블록을 제외한 여러가] 수 (https://stackoverflow.com/questions/6095717/python-one-try-multiple-except)이 실제로 훨씬 더 우아하고 나에게 기분이 – JETM

답변

0

특정 예외 클래스와 재귀를 사용하면 좀 더 건조해질 수 있습니다. 이들 라인을 따른 Sth :

class Retry(Exception): 
    def __init__(self, e): 
     super(Exception, self).__init__() 
     self.e = e 

def run(max_retries=10, exc=None): 
    if max_retries <= 0: 
     raise exc or Exception('Whatever') 
    try: 
     try: 
      result = run_operation() 
     except OneTypeOfError as e: 
      raise Retry(e) 
     if result.another_type_of_error: 
      raise Retry(AnotherTypeOfError()) 
     try: 
      result.do_a_followup_operation() 
     except AThirdTypeOfError as e: 
      raise Retry(e) 
    except Retry as r: 
     return run(max_retries=max_retries-1, exc=r.e) 
    else: 
     return result 

주어진 반복 수를 갖는 반복 솔루션은 의미 론적으로 의문의 여지가있다. 결국, 당신은 모든 일이 성공하기를 원하고 재 시도는 하나의 대결이됩니다. 재시도가 부족하여 기본 케이스처럼 들립니다.

+0

아하 - 감사합니다 당신! – nonagon

0

편집 :

try: 
    # do something 
except OneTypeOfError as e: 
    # handle one type of error one way 
    print(e) # if you want to see the Exception raised but not raise it 
except AnotherTypeOfError as e: 
    # handle another type of error another way 
    raise e('your own message') 
except (ThirdTypeOfError, FourthTypeOfError) as e: 
    # handle error types 3 & 4 the same way 
    print(e) # if you want to see the Exception raised but not raise it 
except: # DONT DO THIS!!! 
    ''' 
    Catches all and any exceptions raised. 
    DONT DO THIS. Makes it hard to figure out what goes wrong. 
    ''' 
else: 
    # if the try block succeeds and no error is raisedm then do this. 
finally: 
    ''' 
    Whether the try block succeeds or fails and one of the except blocks is activated. 
    Once all those are done with, finally run this block. 
    This works even if your program crashed and so is great for cleaning up for example. 
    ''' 

내가 한 : 아 난 당신의 코드가 JETM

여기 ExceptionHandling에 당신의 빠른 프라이머의 지적대로 블록을 제외하고 복수를 사용하지 않은 표시 몰랐어요 이것은 한때 오래 전이었고 예외적으로 한 종류의 함수에서 재귀 적으로 동일한 함수를 호출했지만 다른 함수에서는 호출하지 않았습니다. 또한 재시도 인덱스와 max_retries 변수를 함수에 전달했습니다.이 매개 변수를 매개 변수로 추가해야했습니다.

다른 방법은 전체를 max_retries의 for 루프에 배치하고 재시도를 원하지 않는 예외에 대해 블록을 제외한 모든 블록에 휴식을 추가하는 것입니다.

마지막으로 for 루프 대신 전체 루프를 while 루프에 넣고 하나의 예외 유형을 제외하고 증분 조건을 블록에 삽입하고 while 예외 조건을 false로 설정하면 다른 예외를 제외하고 false가됩니다.

0

내가 올바르게 이해하는 경우 두 가지 변경하여 다음과 같이, 당신은 그것을 할 수 : 0 더 자연스럽게 읽고 당신이 양수라는 것을 악용 할 수 있습니다부터 10 아래로 tries_left 계산

  • 을 대신 retry_index 진실. 이미 result.another_error이 참 AnotherTypeOfError 경우 올릴 것이라고

    당신이 변경 (또는 포장) 경우
  • run_operation() 같은, 당신은 처음 두 except 블록을 결합 할 수있다.

코드는 선택적으로 elseraise (또는 대신 if tries_left을 테스트하도록 선택하는 경우 continue이 후) 생략하여 약간 더 조밀 할 수 - 제어 흐름 어쨌든 그 시점에서 전환된다 -, 퍼팅에 의해 벌레와 같은 줄에 간단한 문이 else없이 if입니다.

for tries_left in range(10, -1, -1): 
    try: 
     result = run_operation() 
    except OneTypeOfError, AnotherTypeOfError: 
     if not tries_left: raise 
     continue 

    try: 
     result.do_a_followup_operation() 
    except AThirdTypeOfError: 
     if not tries_left: raise 
     continue 

    return result