programing

Python에서 오류가 없을 때까지 시도합니다.

skycolor 2023. 7. 21. 21:29
반응형

Python에서 오류가 없을 때까지 시도합니다.

Python에는 서버에 액세스하고 있으며 때때로 해당 서버에 500개의 내부 서버 오류가 있기 때문에 오류가 발생할 가능성이 높은 코드가 있습니다.오류가 발생하지 않을 때까지 계속 시도하고 싶습니다.해결책은 다음과 같습니다.

while True:
    try:
        #code with possible error
    except:
         continue
    else:
         #the rest of the code
         break

이것은 저에게 해킹처럼 보입니다.이것을 하는 더 파이썬적인 방법이 있습니까?

그것은 더 깨끗해지지 않을 것입니다.이것은 매우 깨끗한 일이 아닙니다.기껏해야 (어쨌든 그것은 더 읽을 수 있을 것이다, 왜냐하면 조건이 있기 때문이다.break저 위에 그들과 함께 있습니다.while , 할 수 .result = None그리고 그것을 하는 동안 루프.is None, 변수를 바꿀 .continue의▁the옳으로.pass(입니다.) (오류가 발생해도 상관없습니다.) 그리고 (오류를 삭제합니다.break이것은 또한 한 번만 실행되는 나머지 코드를 루프 밖으로 가져옵니다. bare 한또 맨b(베어)도 하십시오.except:조항은 문서에 제시된 이유로 사악합니다.

위의 모든 것을 통합한 예:

result = None
while result is None:
    try:
        # connect
        result = get_data(...)
    except:
         pass
# other code that uses result but is not involved in getting it

여기 4번의 시도 후 하드가 실패하고 시도 사이에 2초를 기다리는 것이 있습니다.원하는 것을 얻기 위해 변경합니다.

from time import sleep

for x in range(0, 4):  # try 4 times
    try:
        # msg.send()
        # put your logic here
        str_error = None
    except Exception as str_error:
        pass

    if str_error:
        sleep(2)  # wait for 2 seconds before trying to fetch the data again
    else:
        break

다음은 백오프의 예입니다.

from time import sleep

sleep_time = 2
num_retries = 4
for x in range(0, num_retries):  
    try:
        # put your logic here
        str_error = None
    except Exception as e:
        str_error = str(e)

    if str_error:
        sleep(sleep_time)  # wait before trying to fetch the data again
        sleep_time *= 2  # Implement your backoff algorithm here i.e. exponential backoff
    else:
        break

아마도 이런 것들이 있을 것입니다.

connected = False

while not connected:
    try:
        try_connect()
        connected = True
    except ...:
        pass

오류로 인해 재시도할 때 항상 다음을 수행해야 합니다.

  • 재시도 제한을 구현하지 않으면 무한 루프에서 차단될 수 있습니다.
  • 지연을 구현하지 않으면 CPU 또는 이미 문제가 있는 원격 서버와 같은 리소스를 너무 세게 망치질할 수 있습니다.

이러한 문제를 해결하면서 이 문제를 해결하는 간단한 일반적인 방법은 백오프 라이브러리를 사용하는 것입니다.기본적인 예:

import backoff

@backoff.on_exception(
    backoff.expo,
    MyException,
    max_tries=5
)
def make_request(self, data):
    # do the request

이 코드는 재시도 로직을 구현하는 데코레이터로 make_request를 래핑합니다. 오류가 발생할 마다 다시 합니다.MyException발생하며, 재시도 횟수는 5회로 제한됩니다.이러한 맥락에서 지수적인 백오프는 재시도가 원격 서버에 미치는 추가적인 부담을 최소화하는 데 도움이 되는 좋은 아이디어입니다.

이 레시피는 "예외가 발생할 때까지 함수를 반복적으로 호출"하는 아이디어를 요약합니다.이것은 허용된 답과 비슷하지만, 레시피는 대신 반복기를 제공합니다.

레시피에서:

def iter_except(func, exception, first=None):
    """ Call a function repeatedly until an exception is raised."""
    try:
        if first is not None:
            yield first()            # For database APIs needing an initial cast to db.first()
        while True:
            yield func()
    except exception:
        pass

당신은 확실히 후자의 코드를 직접 구현할 수 있습니다.편의를 위해 이 레시피를 구현하는 별도의 라이브러리를 사용합니다(선택 사항).

코드

import more_itertools as mit

list(mit.iter_except([0, 1, 2].pop, IndexError))
# [2, 1, 0]

세부 사항

, 여, 서기.pop주어진 함수)는 반복에 됩니다.IndexError상승했습니다.

의 신의경우때, 을고할려몇몇당▁some.connect_function그리고 예상 오류, 예외가 발생할 때까지 함수를 반복적으로 호출하는 반복기를 만들 수 있습니다.

mit.iter_except(connect_function, ConnectionError)

이 시점에서 루프오버 또는 호출을 통해 다른 반복기로 처리합니다.next().

여기 성공할 때까지 재시도를 더 깔끔한 패키지로 포장하기 위해 작성한 유틸리티 기능이 있습니다.동일한 기본 구조를 사용하지만 반복을 방지합니다.마지막 시도에서 예외를 비교적 쉽게 잡았다가 다시 던지도록 수정할 수 있습니다.

def try_until(func, max_tries, sleep_time):
    for _ in range(0,max_tries):
        try:
            return func()
        except:
            sleep(sleep_time)
    raise WellNamedException()
    #could be 'return sensibleDefaultValue'

그러면 이렇게 부를 수 있습니다.

result = try_until(my_function, 100, 1000)

를 수를전하경에 전달해야 할 my_function당신은 이것을 가질 수도 있습니다.try_until인수를 전달하거나 인수 없음 람다로 감아서 다음과 같이 입력합니다.

result = try_until(lambda : my_function(x,y,z), 100, 1000)

아마 장식가를 기반으로?재시도할 예외 및/또는 시도 횟수의 예외 목록을 장식자 인수 목록으로 전달할 수 있습니다.

def retry(exceptions=None, tries=None):
    if exceptions:
        exceptions = tuple(exceptions)
    def wrapper(fun):
        def retry_calls(*args, **kwargs):
            if tries:
                for _ in xrange(tries):
                    try:
                        fun(*args, **kwargs)
                    except exceptions:
                        pass
                    else:
                        break
            else:
                while True:
                    try:
                        fun(*args, **kwargs)
                    except exceptions:
                        pass
                    else:
                        break
        return retry_calls
    return wrapper


from random import randint

@retry([NameError, ValueError])
def foo():
    if randint(0, 1):
        raise NameError('FAIL!')
    print 'Success'

@retry([ValueError], 2)
def bar():
    if randint(0, 1):
        raise ValueError('FAIL!')
    print 'Success'

@retry([ValueError], 2)
def baz():
    while True:
        raise ValueError('FAIL!')

foo()
bar()
baz()

물론 'try' 부분은 두 루프 모두에서 사용하기 때문에 다른 함수로 이동해야 하지만 이것은 예시일 뿐입니다;)

다른 대부분의 사람들처럼, 저는 제한된 횟수를 시도하고 시도 사이에 잠을 자는 것을 추천합니다.이렇게 하면 원격 서버에 실제로 문제가 발생할 경우 무한 루프 상태가 되지 않습니다.

또한 예상되는 특정 예외가 발생한 경우에만 계속 진행하는 것이 좋습니다.이렇게 하면 예상치 못한 예외를 처리할 수 있습니다.

from urllib.error import HTTPError
import traceback
from time import sleep


attempts = 10
while attempts > 0:
    try:
        #code with possible error
    except HTTPError:
        attempts -= 1
        sleep(1)
        continue
    except:
        print(traceback.format_exc())

    #the rest of the code
    break

또한, 다른 블록이 필요하지 않습니다.except 블록에서 계속 진행되기 때문에 시도 블록이 작동하거나, while 조건이 충족되거나, HTTP 오류 이외의 예외가 발생할 때까지 나머지 루프를 건너뜁니다.

파이피의 라이브러리를 다시 시도하는 것은 어떻습니까?제가 한동안 사용한 적이 있는데 정확히 제가 원하는 대로 작동합니다(오류 시 재시도, 없음 시 재시도, 시간 초과 시 재시도).다음은 해당 웹 사이트의 예입니다.

import random
from retrying import retry

@retry
def do_something_unreliable():
    if random.randint(0, 10) > 1:
        raise IOError("Broken sauce, everything is hosed!!!111one")
    else:
        return "Awesome sauce!"

print do_something_unreliable()
e = ''
while e == '':
    try:
        response = ur.urlopen('https://https://raw.githubusercontent.com/MrMe42/Joe-Bot-Home-Assistant/mac/Joe.py')
        e = ' '
    except:
        print('Connection refused. Retrying...')
        time.sleep(1)

이게 통할 겁니다.이 설정은 "로 설정되며, 가 루프가 여전히 "인지 확인합니다.try 문에 오류가 발견되면 연결이 거부되었음을 출력하고 1초 동안 기다렸다가 다시 시작합니다.시도에 오류가 없을 때까지 계속 진행되며, ' '로 설정하여 while 루프를 종료합니다.

저는 지금 이것을 시도하고 있습니다, 이것이 제가 생각해낸 것입니다;

    placeholder = 1
    while placeholder is not None:
        try:
            #Code
            placeholder = None
        except Exception as e:
            print(str(datetime.time(datetime.now()))[:8] + str(e)) #To log the errors
            placeholder = e
            time.sleep(0.5)
            continue

다음은 오류를 문자열로 캡처하는 데 사용하는 짧은 코드입니다.성공할 때까지 재시도합니다.이렇게 하면 모든 예외가 적용되지만 원하는 대로 변경할 수 있습니다.

start = 0
str_error = "Not executed yet."
while str_error:
    try:
        # replace line below with your logic , i.e. time out, max attempts
        start = raw_input("enter a number, 0 for fail, last was {0}: ".format(start))
        new_val = 5/int(start)
        str_error=None
    except Exception as str_error:
         pass

경고: 이 코드는 예외가 발생하지 않을 때까지 영구 루프 상태로 유지됩니다.이는 단순한 예에 불과하며, 더 빨리 루프를 벗어나거나 재시도 사이에 잠을 자야 할 수도 있습니다.

언급URL : https://stackoverflow.com/questions/4606919/in-python-try-until-no-error

반응형